《大设》第七篇之依赖倒置原则
前言
国际惯例,本文写于本人使用《大话设计模式》一书学习设计模式的路上,适用于初学设计模式的道友交流之用,大神误入,请留下您宝贵的意见,感激不尽;
依赖倒置原则
定义
依赖倒置原则的定义可以分为以下三句话:
- 高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象;
- 抽象不应该依赖于具体实现;
- 具体实现应该依赖于抽象;
解释
低层次模块:具有原子逻辑的模块,比如封装的一个函数,或者说一个简单的功能;
高层次模块:具有相对复杂的业务逻辑,是由原子逻辑组合而成的;
依赖:自然界中的依赖可以理解为动物或者植物依赖水氧气等资源,但是在面向对象语言中,依赖可以理解为类A用到了类B,那么A和B之间就存在A依赖于B的关系,这种关系是比较脆弱的,并且具有临时性和偶然性(具体请参考UML类图);
抽象:在JAVA中,抽象主要指的就是接口和抽象类,两者都不能使用构造方法直接实例化;
实现:在JAVA中,实现是指实现了接口的实现类或者是继承了抽象类,并且实现了抽象方法的具体的类;
理解
依赖倒置原则是什么?上面已经给出了定义,但是用我们平常最常听到的一句话就是面向接口编程,但是单单一句面向接口编程是很虚的一句话,说了等于没说,最少我第一次听到这句话的时候懵逼了半天,不知道什么意思,那么今天我们所说的依赖倒置原则或者说是面向接口编程到底表达了一个什么样的意思呢?其实主要有以下两个方面:
- 模块和模块之间采用抽象的方式关联,也就是说两个模块之间的只通过接口或者抽象类来发生联系,具体的实现类之间互相不认识,也就是不发生依赖;
- 接口或者抽象类不依赖于具体的抽象类,但是具体的实现类却要依赖于接口或者抽象类;
应用 举个我们经常使用到的例子来说,相信大家对于JDBC都不陌生,在JDBC中最重要的两个接口分别是Driver和Connection,部分源码如下所示:
package java.sql; import java.sql.DriverPropertyInfo; import java.sql.SQLException; /** * The interface that every driver class must implement. */ public interface Driver { Connection connect(String url, java.util.Properties info) throws SQLException; boolean acceptsURL(String url) throws SQLException; DriverPropertyInfo[] getPropertyInfo(String url, java.util.Properties info) throws SQLException; int getMajorVersion(); int getMinorVersion(); boolean jdbcCompliant(); } package java.sql; import java.sql.PreparedStatement; import java.sql.SQLException; /** * <P>A connection (session) with a specific * database. SQL statements are executed and results are returned * within the context of a connection. * <P> */ public interface Connection extends Wrapper { Statement createStatement() throws SQLException; PreparedStatement prepareStatement(String sql) throws SQLException; }
在Driver接口中有一个connect方法,这个方法的作用是返回给Connection连接,用以操作数据库等操作,Driver接口中有这样一个注释The interface that every driver class must implement.就是说每一个数据库厂商都必须实现这个Driver接口,因此一个数据库厂商,比如mysql或者oracle,都要提供一个数据库驱动类,然后实现Driver接口,调用connect方法生成一个Connection,然后生成的Connection向上转型为java.sql.Connection,而且数据库厂商还需要一个Connection实现类,用来操作具体的数据库操作,以mysql为例,具体的类图如下所示:
此时如果sqlserver也要提供数据库驱动,那么不需要去修改Driver接口和Connection接口,只需要提供sqlserver自己的实现了Driver和Connection接口的数据库驱动类和Connection实现类即可,这样满足了对修改关闭对扩展开放,同时数据库驱动和连接之间使用接口的方式进行关联,并没有使用具体的实现类进行关联,并且没有依赖具体的实现类,满足依赖倒置原则。
为什么叫依赖倒置?
我刚开始看到依赖倒置的名称的时候也比较郁闷,为什么叫依赖倒置呢?后来在这篇文章中发现了一种解释,窃以为比较合理,话说依赖正置是指类之间的依赖是实实在在的实现类之间的依赖,也就是面试实现编程,这也是正常人的思维,但是在编写程序的时候需要的是对现实世界的事物进行抽象,抽象的结果就是有了抽象类和接口,然后我们根据系统设计的需要产生了抽象间的依赖,代替了人们传统思维中的事物间的依赖,依赖倒置就是从这里产生的;
总结
依赖倒置原则要求我们做到面向接口编程,同时结合前面的里式替换原则来说,使用抽象设计与其他类之间的依赖关系,使用实现类准确实现业务逻辑,在适当的时候对父类进行细化,同时依赖倒置原则也是实现开闭原则的重要途径,没有实现依赖倒置,也就无从谈起对修改关闭对扩展开放。
参考文章
- http://www.cnblogs.com/cbf4life/archive/2009/12/15/1624435.html
- http://blog.csdn.net/zhengzhb/article/details/7289269
- http://www.cnblogs.com/zuoxiaolong/p/pattern5.html