软件设计原则----依赖倒置原则(DIP)
来源:互联网 发布:电脑短信软件 编辑:程序博客网 时间:2024/05/17 08:40
“要针对接口编程,不要针对实现编程。”
陈述:
- 高层模块不应该依赖于低层模块。二者应该依赖于抽象。
- 抽象不应该依赖于细节。细节应该依赖于抽象。
- 所谓“倒置”是相对于传统的开发方法(例如结构化方法)中总是倾向于让高层模块依赖于低层模块而言的软件结构而言的。
- 高层包含应用程序的策略和业务模型,而低层包含更多的实现细节,平台相关细节等。高层依赖低层将导致:
- 难以复用。通常改变一个软硬件平台将导致一些具体的实现发生变化,如果高层依赖低层,这种变化将导致逐层的更改。
- 难以维护。低层通常是易变的。
- “……所有良构的OO体系结构都具有清晰的层次定义,每个层次通过一个定义良好的、受控的接口向外提供了一组内聚的服务。”
- 简单的理解
- 更好的理解
下层的实现,依赖于上层的接口
客户拥有接口,而服务者则从这些接口派生
当接受到Poll(轮询)消息时,判断其是否被“按下”。这个按下是抽象的(不关心通过什么样的机制去感知):
- 可能是GUI上的一个按钮被鼠标单击。
- 可能是一个真正的按钮被手指按下。
- 可能是一个防盗装置检测到了运动。
- ……
- 可能是计算机控制台的LED。
- 可能是停车场的日光灯。
- 可能是激光打印机中的激光。
- ……
- Lamp的任何变化都会影响到Button,导致其改写或者重新编译。
- 黑盒方式复用Button来控制一个Motor类变得不可能。
- 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:
- <span style="white-space:pre"> </span>virtual void turnOn()=0;
- <span style="white-space:pre"> </span>virtual void turnOff()=0;
- };
- //lamp.h
- class Lamp:public ButtonServer{
- public:
- <span style="white-space:pre"> </span>void turnOn();
- <span style="white-space:pre"> </span>void turnOff();
- };
- //lamp.cpp
- void Lamp::turnOn(){
- <span style="white-space:pre"> </span>/*codes for turn on a specific device*/
- }
- void Lamp::turnOff(){
- <span style="white-space:pre"> </span>/*codes for turn off a specific device*/
- }
上述设计使得Button可以控制所有愿意实现ButtonServer接口的设备,甚至是一个尚未开发出来的设备。
质疑:
这样的设计是不是强加了这样一个约束——所有需要被Button控制的对象一定要实现ButtonServer类。
如果我的设备还希望能够被另一个对象控制,比如Switch控制,怎么办?
这种设计是不是将Button对Lamp的依赖转嫁成了Lamp对Button的依赖呢?(毕竟Lamp只能被一种Button控制也是不好的)
抗辩:
上述质疑不成立。Button依赖于ButtonServer接口,但是接口并不依赖于Button,也就是说任何知道如何操作ButtonServer接口的对象都可以操作Lamp。
也许需要改进的仅仅是ButtonServer这样一个有些“误导性”的名字,我们可以将这个名字该得更加抽象一些,例如:SwitchableDevice
总结
使用传统过程化设计所创造出来的依赖关系结构,策略是依赖于细节的。----策略受细节改变影响
面向对象程序设计倒置了依赖关系结构,使细节和策略都依赖于抽象,成为面向对象设计的标志。
依赖倒置原则是实现面向对象技术的基本低层机制,有利于复用和维护。
依赖倒置原则假定具体类都是会变化的,避免对具体类的直接引用,可能会导致大量的类。功能强大,最不容易实现。
相应设计模式:
Factory Method
Prototype
Iterator
参考资源:
《设计模式:可复用面向对象软件的基础》,ERICH GAMMA RICHARD HELM RALPH JOHNSON JOHN VLISSIDES著作,李英军 马晓星 蔡敏 刘建中译,机械工业出版社,2005.6
《敏捷软件开发:原则、模式与实践》,Robert C. Martin著,邓辉译,清华大学出版社,2003.9
《设计模式解析》,Alan Shalloway等著(徐言声译),人民邮电出版社,2006.10
转载:http://blog.csdn.net/beyondhaven/article/details/6903780
- 软件设计原则----依赖倒置原则(DIP)
- 软件设计原则----依赖倒置原则(DIP)
- 软件设计原则----依赖倒置原则(DIP)
- 依赖倒置原则(DIP)
- 依赖倒置原则(DIP)
- DIP依赖倒置原则
- 依赖倒置原则--DIP
- 依赖倒置原则--DIP
- 依赖倒置原则--DIP
- 软件设计原则----依赖倒置原则(DIP)http://blog.csdn.net/beyondhaven/article/details/6821091
- 设计模式--------依赖倒置原则(DIP)
- DIP依赖倒置原则(转)
- 设计原则(四)依赖倒置原则(DIP)
- OOD设计原则之依赖倒置原则(DIP)
- 面向对象设计原则二:依赖倒置原则(DIP)
- 六大原则之“依赖倒置原则(DIP)“笔记
- 设计模式六大原则之--依赖倒置原则(DIP)
- 设计模式六大原则---依赖倒置原则(DIP)
- 5.MongoDB中的索引。
- 如何: 连接到一台远程计算机
- matlab assignin导出指定workspace evalin执行指定workspace 命令
- vc2010串口通信(使用mscomm控件)
- [USB] VBUS
- 软件设计原则----依赖倒置原则(DIP)
- MySQL DELAY_KEY_WRITE
- 取模与取余的区别
- myapps平台中对于外部映射表,如何插入一条记录?
- 双核不可阻挡!首款双核处理器Tegra2详解
- 眼睛直观感受几种常用排序算法
- 单元测试实践的主要问题与解决(8)
- 重写"Hello world!"
- Hibernate -annotation 学习笔记