面向接口编程,都快成了程序员的一句口头禅了,但是,真正做到了吗。
你对自己说,对周围的伙伴说,做到了。
怎么做到的。
你看,每个项目中所有的service都有一个interface,一个impl,垒得整整齐齐。
哦。
问,为什么要这么做呢。
说,面向接口编程,防止未来有扩展的时候,不好扩展。
哦。
但,现实是,自从项目上线,从始至终,都未曾有第二种实现方式出现。
但是不这么做的话,又不行,你说,要面向接口编程,都得这样做。
谁需要接口?
接口存在的一个目的是为了解耦,像上面讲到的,把interface 和 impl 垒的相当整齐,实现解耦了吗。
很多研发人员,从业以来,一直会是这么认为的,他们总认为是实现类需要一个接口,我先弄了一个实现impl,想起来,我们要面向接口编程,结果就又搞了一个接口interface。
这是颠倒了。
其实,是消费者需要接口,实现类只是提供一个服务。
因此,应该由消费者,或者叫做客户端,来定义接口。
你比如说,这个业务系统,要使用支付宝,或者微信来完成支付,支付宝和微信是两个具体的实现。要是,有一天需要,再来第三种实现呢,为了这个扩展性,是谁需要一个接口,是这个业务系统。
谁更应该来定义这个接口呢,是业务系统。
这里的业务系统,就是我们上面说的消费者,或者叫做客户端。
而这里的,在支付宝和微信两种实现方式之上的接口,也就是我们从业务上需要的“在线支付能力”。
Martin Fowler曾经提出过role interface和header interface的定义。
如果是站在消费者的角度,来定义接口,就是Role interface。
如果是站在实现者的角度,来定义接口,就是Header interface。
我们应该站在消费者的角度定义Role interface,而不是从实现类中提取Header Interface。
这有什么区别吗,又有什么问题呢。
我找一个例子,一起看看。
先说区别。
什么是Role interface,一块砖头,可以被工人拿去盖房子,也可以在紧急时刻当武器使。
public class Brick {
private int length;
private int width;
private int height;
private int weight;
public void build() {
//...工人盖房
}
public void defense() {
//...普通人正当防卫
}
}
下面这种方式就是Role interface。
public interface BuildHouse {
void build();
}
public interface StrickCompetence {
void defense();
}
public class Worker implement BuildHouse{
public void build() {
//...工人盖房
}
}
public class Person implement StrickCompetence {
public void defense() {
//...普通人正当防卫
}
}
下面这段代码是Header interface,硬生生的定义了一个接口,包含了两个动作,盖房子的和当武器防卫的。
public interface BrickInterface {
void buildHouse();
void defense();
}
会有什么问题吗。
有,如果我就是一名盖房子的工人,我只需要buildHouse()的功能,如果使用Header interface,我就必须被迫依赖并实现defense()的功能,可是我当时并不想,也不需要拿着它来当武器用。
这种做法,也当然违反了接口隔离的原则(SOLID原则之一)。
体会到了接口定义的归属关系,也就体会到了依赖倒置原则的定义和它的真正含义:依赖倒置原则是过程式编程与OO编程的分水岭。
过程式编程,都是依赖具体,自依赖倒置后,A-C,A依赖C,可以变成A-B-C,A先依赖B,结合消费者或者叫做客户端定义接口,B就是那个接口。
----END----
这里记录,我每周碰到的,或想到的,引起触动,或感动的,事物的思考及笔记。不见得都对,但开始思考记录总是好的。
与爱学习、爱思考、爱记录的你共勉。
参考资料
https://time.geekbang.org/column/article/397251 图1 图2选自此文
https://blog.csdn.net/qq_43028950/article/details/112590580