标签:style blog http color 使用 strong 文件 io
定义:
高层次的模块不应该依赖于低层次的模块,两者都应该依赖于抽象接口;抽象接口不应该依赖于具体实现。而具体实现则应该依赖于抽象接口。依赖倒置原则英文全称为Dependence Inversion Principle,简称为DIP。
问题由来:
类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。
解决方案:
将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率。
采用依赖倒置原则可以减少类间的耦合性,提高系统的稳定性,减少并行开发引起的风险,提高代码的可读性和可维护性。依赖倒置原则的核心就是面向接口编程,理解了面向接口编程也就理解了依赖倒置原则。下面通过一个司机开车的例子简单说明一下:
有一个奔驰车类,奔驰车可以运行,方法为Run,司机类有一个开奔驰车的方法Drive。司机和奔驰车类的代码如下所示:
///<summary> /// 奔驰车类 ///</summary> public class Benz { //奔驰车运行 public void Run() { Console.WriteLine("奔驰车开始运行..."); } } ///<summary> /// 司机类 ///</summary> public class Driver { public void Drive(Benz benz) { benz.Run(); } }
主函数司机小明开动奔驰车,代码如下:
class Client { static void Main(string[] args) { //一辆奔驰车 var benz = new Benz(); //司机小明 var xiaoming = new Driver(); //小明开奔驰 xiaoming.Drive(benz); Console.ReadKey(); } }
上面实现了司机开奔驰车的场景,但是对于实际的业务来说,需求是不断变化的。在技术上"变更才显真功夫",只有在"变化"过程中才能知道自己设计或程序是否是松耦合。上面的例子,我们加点要求:司机也要会开宝马车。要完成这个必须先有个宝马车类,如下所示:
///<summary> /// 宝马车类 ///</summary> public class Bmw { //宝马车运行 public void Run() { Console.WriteLine("宝马车开始运行..."); } }
尽管有了宝马车类,但是司机根本木有开宝马车的方法。你可能会说,木有那就加上开宝马车的方法!这样,是解决了一时的问题,但是还有法拉利、宾利等车呢?因此,是我们的设计出现了问题:司机类和奔驰车类之间是一个紧耦合的关系,其导致的结果就是系统的可维护性大大降低,可读性降低,两个相似的类需要阅读两个文件,这显然不可取。还有稳定性:固化的、健壮的才是稳定的。这里只是增加了一个车类就需要修改司机类,这不是稳定性,这是易变性。被依赖者的变更竟然让依赖者来承担修改的成本,这样的依赖关系谁肯承担!
在实际项目的开发中,要尽可能减少并行开发引起的风险。并行开发最大的风险就是风险扩散,本来只是一段程序的错误或异常,逐步波及一个功能,一个模块,甚至到最后毁坏了整个项目。因为一个团队,几十人甚至上百人人开发,各人负责不同的功能模块,甲负责汽车类的建造,乙负责司机类的建造,在甲没有完成的情况下,乙是不能完全地编写代码的,缺少汽车类,编译器根本就不会让你通过!在缺少Benz类的情况下,Driver类能编译吗?更不要说是单元测试了!这种相互依存的关系在实际开发中是不被允许的,另一个角度来说这样开发只能挨个进行修改,并且每一项修改可能牵一发而动全身。这种模式 在现在的大中型项目中已经是完全不能胜任了,一个项目是一个团队的协作结果,一个人不可能了解所有的业务和所有的技术,要协作就要并行开发,要并行开发就要解决模块之间的项目依赖关系,然后依赖倒置原则就隆重出场了,呵呵。
依赖倒置原则的核心就是接口,下面我们为车和司机定义两个接口ICar和IDriver,代码如下所示:
///<summary> /// 汽车接口 ///</summary> public interface ICar { void Run(); } ///<summary> /// 司机接口 ///</summary> public interface IDriver { void Drive(ICar car); }
然后让上面定义的司机和汽车(宝马和奔驰)各自继承自己对应的接口,代码如下所示:
///<summary> /// 奔驰车类 ///</summary> public class Benz:ICar { //奔驰车运行 public void Run() { Console.WriteLine("奔驰车开始运行..."); } } ///<summary> /// 宝马车类 ///</summary> public class Bmw:ICar { //宝马车运行 public void Run() { Console.WriteLine("宝马车开始运行..."); } } ///<summary> /// 司机类 ///</summary> public class Driver:IDriver { public void Drive(ICar car) { car.Run(); } }
此时的类的结构图如下所示:
在开发实现业务需求时,我们应该谨记抽象不依赖细节。在这里,汽车和司机的接口都不依赖细节(具体的实现类),看到这应该对依赖倒置原则理解的差不多了吧。
依赖倒置原则是一个指导思想,是通过抽象(接口或抽象类)使各个类或模块的实现彼此独立,不互相影响,实现模块间的松耦合,为更好使用此原则,在实际项目中我们要按如下方法使用:
依赖倒置原则是六个设计原则中最难以实现的原则,它是实现开闭原则的重要途径,依赖倒置原则没有实现,就别想实现对扩展开放,对修改关闭。在项目中,大家只要记住是"面向接口编程"就基本上抓住了依赖倒转原则的核心。顺便说一下,实际的项目投产上线和盈利是第一要务,因此设计模式的原则只是提供了指导思想,我们不应该主动去违背,但是限于实际情况不得不违背,否则即便设计得有多么好,架构多么完美,这都是扯淡的事情。一旦超过预期工期或者项目亏本,你老板不高兴,然后你也会不高兴的…
设计模式六大原则(3)--依赖倒置原则,布布扣,bubuko.com
标签:style blog http color 使用 strong 文件 io
原文地址:http://www.cnblogs.com/binghuojxj/p/3868115.html