软件设计原则----依赖倒置原则(DIP)
"要依赖于抽象,不要依赖于具体。”
“要针对接口编程,不要针对实现编程。” 陈述:
分析:
层次化:
对上述论述可能存在两种不同的理解:
1)依赖关系倒置
下层的实现,依赖于上层的接口
2)接口所有权倒置
客户拥有接口,而服务者则从这些接口派生
我们可以分两种模式来定义:
1、依赖不倒置的开发:自顶向下首先设计整个软件的分解结构,然后首先实现下层的功能,再实现上层的功能,并使上层调用下层函数。
2、依赖倒置的开发:首先设计上层需要调用的接口,并实现上层,然后低层类从上层接口派生,实现低层。在这种情况下,
接口属于上层。
实例
我们来看一下Button与Lamp:
Button(开关)感知外界的变化。
当接受到Poll(轮询)消息时,判断其是否被“按下”。这个按下是抽象的(不关心通过什么样的机制去感知):
初步设计
Button对象直接依赖Lamp对象,从而:
class Button{ Lamp * itsLamp; public: void poll( ){ if(/* some condition */) itsLamp->turnOn( ); .... } };问题 上面的设计违反了DIP。应用程序的高层策略没有和低层实现分离;抽象没有和具体细节分离。 改进思路
改进后的设计: Button依赖于抽象的接口ButtonServer(向该接口发消息)。ButtonServer提供一些抽象的方法,Button类通过这些接口可以开启或关掉一些东西。 Lamp也依赖于ButtonServer接口(从此接口派生),提供具体的实现。 如下图所示: 部分代码: //Button.h #include "ButtonServer.h" class Button{ ButtonServer * bs; public: void poll( ); }; //Button.cpp void Button::poll( ){ if(/* mechanism for detecting turnOn command */) bs->turnOn( ); else if((/* mechanism for detecting turnOff command */) bs->turnOff( ); } //ButtonServer.h class ButtonServer{ public: virtual void turnOn()=0; virtual void turnOff()=0; }; //lamp.h class Lamp:public ButtonServer{ public: void turnOn(); void turnOff(); }; //lamp.cpp void Lamp::turnOn(){ /*codes for turn on a specific device*/ } void Lamp::turnOff(){ /*codes for turn off a specific device*/ }分析 上述设计使得Button可以控制所有愿意实现ButtonServer接口的设备,甚至是一个尚未开发出来的设备。 质疑: 抗辩: 总结 使用传统过程化设计所创造出来的依赖关系结构,策略是依赖于细节的。----策略受细节改变影响 相应设计模式:
参考资源: 《设计模式:可复用面向对象软件的基础》,ERICH GAMMA RICHARD HELM RALPH JOHNSON JOHN VLISSIDES著作,李英军 马晓星 蔡敏 刘建中译,机械工业出版社,2005.6 《敏捷软件开发:原则、模式与实践》,Robert C. Martin著,邓辉译,清华大学出版社,2003.9 《设计模式解析》,Alan Shalloway等著(徐言声译),人民邮电出版社,2006.10 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |