在 一文get到SOLID原则的重点 和 SOLDI原则之DIP:依赖倒置原则 里提到过DIP (依赖倒置原则)里提到过接口所有权的问题。今天再次聊下接口所有权。
在《敏捷软件开发:原则、模式与实践》里作者提到了一个开关和台灯设计的例子。
图1
图1的设计中,Switch 对象可以轮询真实的开关的状态 ,并且可以发送相应的turnOn 和turnOff 消息给Light。这个设计不好在哪里? 它违反了依赖倒置原则(DIP)和开放封闭原则(OCP)。对DIP违反比较明显,Switch 依赖了具体的类,DIP 要依赖于抽象类。对于OCP 的违反不明显,但切中要害。不能容易的扩展Switch 去管理除Light外的其他对象。
作者提出了简单的设计模式Abstract Server模式,如图2。模式也许没有听过,但一定这样用过。我们在Switch 和Light 之间引入一个接口,这样就使得Switch 能够控制任何实现了这个接口的东西。这就满足了DIP和OCP。
图2
再来看一个例子,微软为了展示.Net企业系统开发的能力。曾经发布过一个PetShop作为范例,后来很多企业系统的架构都采用了参照了或简化了此架构设计。标准的三层架构。
从上图所知,业务层对数据访问层抽象出来的IDAL模块。除了解除了向下的依赖之外,对于其上的业务逻辑层,相同仅存在弱依赖关系。那么来看这个设计满足了DIP:依赖倒置原则的高层模块不应该依赖于低层模块,二者都应该依赖于抽象。那么IDAL接口层的所有权属于谁的?以前一直有这个疑问直到看到这一章疑问解决了。通常认为IDAL接口层属于DAl层,那是不对的。这里的IDAL接口的所有权是属于BLL层了。
关于接口所有权的描述,作者说到在20世纪初,我们通常认为实体关系支配着一切。有很多名著都建议把继承层次结构一起放到一个包中。似乎是合理的,继承是非常强的实体关系。但在最近10年中(这本书中文版是2003年出的),我们认识到继承的实体强度是一个误导,并且继承层次结构通常也不应该被打包在一起,相反,往往客户和它们控制的接口打包在一起。换言之客户和接口之间的逻辑关系要强于接口和它的派生类之间的逻辑绑定关系。接口属于它的客户,而不是它的派生类。
这里的接口有的人也称为SPI ,不同一行业标准的SPI,意思是系统内部的标准接口,内部都依赖于这个SPI,用这种模式可实现系统对外部系统的隔离,解耦外部的系统。如果SPI可以做为上下游的接口标准,那么可以由它们来实现。如果做不到,这个SPI 由系统内部自己去实现,只有实现是依赖到三方接口的,这样如果三方接口有替换,我们可以用新的实现去扩展就好了。
结论:
接口所有权属于它的客户,这里的所有权指逻辑关系和打包和发布。由客户模块或者层来声明它们所需要的服务接口,那么仅当客户需要时才会对接口改变。这样改变实现抽象接口的类就不会影响到客户。完全做到实现是可扩展,可替换。
相关阅读: