面向接口设计与角色接口

简介: 面向接口设计与角色接口

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

回答:

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


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

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

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


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

public interface EmailSender {
    void send(Message message);
}
public interface EmailReciever {
    Message[] receive();
}

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

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

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

回答:

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

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

回答:

好处包括:

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


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

public interface Account {
    void credit(Money amount);
    void debit(Money amount);
}
void transfer(Account source, Account destination);

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

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

public interface Source {
    void credit(Money amount);
}
public interface Destination {
    void debit(Money amount);
}

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

void transfer(Source source, Destination destination);

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

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

相关文章
|
4天前
|
安全 前端开发 NoSQL
如果让你设计一个接口,你会考虑哪些问题?
接口设计需关注参数校验、扩展性、幂等性、日志、线程池隔离、异常重试、异步处理、查询优化、限流、安全性、锁粒度和避免长事务。入参与返回值校验确保数据正确性;考虑接口扩展性以适应不同业务需求;幂等设计防止重复操作;关键接口打印日志辅助问题排查;核心接口使用线程池隔离确保稳定性;异常处理中可采用重试机制,注意超时控制;适合异步的场景如用户注册后的通知;并行查询提升性能;限流保护接口,防止过载;配置黑白名单保障安全;适当控制锁粒度提高并发性能;避免长事务影响系统响应。
|
6天前
|
JSON 数据格式
如何创建接口,设计过接口
项目遵循Restful规范设计接口,请求路径基于资源命名,如查询用GET,新增用POST,修改用PUT,删除用DELETE。GET参数通过问号或路径传递,POST/PUT用JSON。统一的接口规范规定:返回数据多时,用VO过滤或整合数据。
13 0
|
6天前
|
设计模式 XML C++
C++组合模式探索:以统一接口管理复杂的层次结构
C++组合模式探索:以统一接口管理复杂的层次结构
39 1
|
7月前
|
设计模式 Java
JAVA设计模式10:外观模式,使得客户端可以通过简单的接口与子系统交互
JAVA设计模式10:外观模式,使得客户端可以通过简单的接口与子系统交互
|
11月前
|
SQL 负载均衡 Java
怎么设计一个高质量的接口API设计
什么是幂等性?对于同一笔业务交易,不管调用多少次,只会成功处理一次。二、幂等性设计我们转账业务为例,来说明一下这个问题,转账接口一定要做到幂等性,否则会出现重复转账的问题。调用转账接口从A中转100元资金给B,参数中会携带业务流水号biz_no和源账户A,目的账户B,和转账金额100,业务流水号biz_no是唯一的。转账接口实现有以下实现方式。
|
安全 前端开发 物联网
接口设计篇《怎么设计好的接口?》
这样设计接口【升职加薪】?
360 0
接口和抽象的使用场景
接口和抽象的使用场景
120 0
|
API
接口设计
接口设计
134 0
|
SQL 设计模式 消息中间件
接口设计需要考虑的问题
接口设计需要注意的问题
1492 0
接口设计需要考虑的问题
|
架构师 Java Go
第五章 接口3 -- 接口的设计原则
接口的设计原则有很多. 今天我们来研究两种. 后面在陆续研究 1. 开闭原则 2. 依赖倒置原则
309 0
第五章 接口3 -- 接口的设计原则