面向接口设计与角色接口

标签 | 软件设计

字数 | 1876字

阅读 | 5分钟

问题:在做项目的时候,是不是所有包含非静态方法的类,都要写一个接口?是因为这样的目的是为了解耦,然后通过DI注入实现吗?

回答:

这不是提取接口的根本原因。因为要做到解耦和DI,直接用类也是可以的,尤其Java的普通方法都是允许子类override的。此外,如果你的接口永远都只有一个实现类,并没有任何可能的需求变化,那么还有必要解耦吗?

所以说,不能死板的将类的方法提取接口,然后美其名曰为面向接口设计。我们不能误解“面向接口设计”原则,该原则所指的“接口”并非Java语言中的interface类型,而是指面向调用者对外暴露的接口,代表一种交互与协作,是对信息的隐藏和封装,而不是具体的interface类型。即使是普通的java方法仍然满足隐藏细节的原则,如果是public的,就可以认为该方法是“面向接口设计”中的接口,也就是说:不要针对实现细节编程,而是针对接口编程。

针对java中的interface类型,包含了两种含义:

  • 接口代表一种能力。例如在Java JDK中定义了很多这种接口,如Runnable, Cloneable, Seriazable
  • 接口代表业务场景中与其他类型协作的角色。从语法特性看,就是对履行职责的角色的抽象。Martin Fowler将其称之为Role Interface(角色接口)。

例如邮件的收发业务。如果收邮件和发邮件可能会被用到不同的使用场景,换言之,这两个方法不会要求必须同时出现,那么就可以分别为其定义两个接口EmailSender, EmailReceiver

但是,我们可以定义一个类EmailService同时实现这两个接口,这就是所谓的“大对象、小接口”,又或者说是接口隔离原则的体现。

如果你先定义了一个类叫EmailService,然后因为你需要定义接口对其抽象,然后就简单地将这个类的所有公有方法都提取到抽象的接口中,这样设计的接口,被Martin Fowler称为Header Interface。欲知Role Interface与Header Interface,可以参考Martin Fowler的这篇文章 。

问题:收发邮件被用到不同的使用场景,怎么理解?

回答:

比如说,在通知模块中,就只会用到发邮件这个方法,不会用到收邮件;在垃圾邮件识别器功能中,就只会用到收邮件这个功能。

问题:那这样做有什么好处?

回答:

好处包括:

  • 分解到不同的独立接口,你就可以针对不同变化独立演化,而不是让收与发同时变化。
  • 你可以有效地重用,而不是非得把包含所有方法的类都放进去。
  • 可以更好地提高编码可读性,以及类型验证,保证代码的健壮性。

例如说转账服务,一个是转出(credit),一个是转入(debit)。一种方法是定义一个接口Account,提供转入和转出的方法。定义的转账服务方法为:

这个方法只是从形参的名称体现了转出源与转入目标,这种依靠参数名称对转入和转出账户的顺序做约束是不可靠的。当我们在实现transfer()方法时,也有可能错误地调用Account的方法,导致潜在的bug。

如果我们基于转出上下文和转入上下文分别识别参与的角色,就可以提出两个接口SourceDestination

转账的服务方法就可以定义为:

你觉得哪个方法更安全、更可读?显然是后者,这就是建立角色接口的好处。

本文链接: http://zhangyi.xyz/interface-oriented-design-and-role-interface/


❈ 题图为Design is Fine. History is Mine,来自Mono《设计笔记》专栏。

原文发布于微信公众号 - 逸言(YiYan_OneWord)

原文发表时间:2018-06-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏CSDN技术头条

Go语言实践:从新手入门到上线真实的小型服务所遇到的那些坑

Teamwork团队在去年写了近20万行Go代码,建造了一堆速度奇快的小型HTTP服务,本文列出了他们总结的9条经验教训。 为什么选择Go语言?Go语言,又称G...

2247
来自专栏Java帮帮-微信公众号-技术文章全总结

第一天 Java基础入门【悟空教程】

3867
来自专栏杨建荣的学习笔记

初识YAML

晚上本来想看看Julia语言的,最后发现需要花额外的不少时间,就先放放,那就看看Yaml吧,要学习的话,周期短,本身也比较简单清晰。 早些年的...

2847
来自专栏安恒网络空间安全讲武堂

适合破解新手的160个crackme练手之04

适合破解新手的160个crackme练手之04 老规矩,先运行程序看看是干嘛的,可以看到程序有点怪异,没有确定按钮,后面知道了原来点击中间阴影部分就是验证功能啦...

2348
来自专栏阮一峰的网络日志

都柏林核心(Dublin Core)

在上一篇日志中,我介绍了元数据(MetaData),并且说只要有一个集合,就可以定义一套元数据。 这样一来,很自然的,我们就会想到一个问题:有没有可能定义一套通...

2817
来自专栏一个会写诗的程序员的博客

程序的基本概念

程序的基本概念 1.1. 程序和编程语言 程序(Program)告诉计算机应如何完成一个计算任务,这里的计算可以是数学运算,比如解方程,也可以是符号运算,比...

1142
来自专栏PHP在线

MySQL时间函数,用起来比PHP还爽

前一篇写了PHP的时间函数(还是草稿),这一篇就写Mysql的时间函数吧。最近做的项目,关乎权限,于是自然而然的就与有效期联系在了一起。其 中有一个功能是生成特...

3446
来自专栏知晓程序

开发 | 让小程序用上「指纹识别」,只需这 3 个接口

最初,小程序文档中只有具体接口调用方法,并没有给出小程序中调用指纹识别的最佳实践。

1350
来自专栏机器学习实践二三事

Numpy使用1

Numpy介绍 NumPy is the fundamental package for scientific computing with Python. I...

2049
来自专栏java一日一条

Java多线程并发锁和原子操作,你真的了解吗?

对于Java多线程,接触最多的莫过于使用synchronized,这个简单易懂,但是这synchronized并非性能最优的。今天我就简单介绍一...

1023

扫码关注云+社区

领取腾讯云代金券