设计原则(五):依赖倒转原则

star2017 1年前 ⋅ 646 阅读

实现 开-闭 原则的关键是 抽象化,并且从抽象化导出具体化实现。如果说 开-闭 原则是面向对象设计的目标的话,依赖倒转 原则就是这个面向对象设计的主要机制。

在Java中,抽象就是指接口或者抽象类,两者都是不能直接被实例化的;细节就是实现类,实现接口或者继承抽象类而产生的就是细节,以关键字 new 产生对象。

Robert C. Martin 在他的著作《敏捷软件开发:原则、模式与实践》中有这样的两句描述:

  • High-level modules should not depend onlow-level modules. Both should depend on abstractions.(高层模块不应该依赖于低层模块,二者都应该依赖于抽象)
  • Abstractions should not depend upondetails. Details should depend upon abstractions.(抽象不应该依赖于具体实现细节,而具体实现细节应该依赖于抽象)

即,模块类之间的依赖是基于抽象类的,实现类之间不能有直接的依赖关系,其依赖关系是通过接口或者抽象类产生的。其核心思想是:要面向接口编程,不要面向实现编程。

什么是依赖倒转

依赖倒转原则讲的是:要依赖于抽象,不依赖于具体(细节)。把抽象层依赖于具体层这种错误的依赖关系倒转过来。

不同的表述:

第一种表述:要针对接口编程,不要针对实现编码。

第二种表述,GOF95 一书所强调的:针对接口编程的意思是,应当使用 Java 接口和抽象类进行变量的类型声明、参量的类型声明,方法的返还类型声明,以及数据类型的转换等。

不要针对实现编程的意思是说,不应当使用具体类进行变量的类型声明,参量的类型声明,方法的返还类型声明,以及数据类型的转换等。

要保证做到这一点,一个具体 Java 类应当只实现 Java 接口和抽象 Java 类中声明过的方法,而不应当给出多余的方法。倒转依赖关系强调一个系统内的实体之间关系的灵活性。基本上,如果设计师希望遵守 开-闭原则,那么 依赖倒转 原则便是达到要求的途径。

抽象层:包含系统宏观层面的逻辑,对整个系统来说是重要的战略性决定,是较为稳定的,是必然性的体现。

实现层:包含一些次要的与实现有关的算法和业务逻辑,是战术性的决定,带有相当大的偶然性选择。

基于复用与维护的【倒转】,应当将复用的重点放在抽象层次上。如果抽象层的模块相对独立于具体实现层模块的话,那么抽象层的模块的复用便相对较为容易。

三种耦合关系

在面向对象的系统里,两个类之间可以发生三种不同的耦合关系:

  • 零耦合(Nil Coupling)关系:如果两个类没有耦合关系,就称之为零耦合。
  • 具体耦合(Concrete Coupling)关系:具体性耦合生在两个具体的(可实例化的)类之间,经由一个类对另一个具体类的直接引用造成。
  • 抽象耦合(Abstract Coupling)关系:

变量的静态类型与实际类型

变量被声明时的类型叫做变量的静态类型,或叫明显类型。变量所引用的对象的真实类型叫做变量的 实际类型

示例如下:List employees = new Vector(); List 是变量的静态类型,Vector 是变量的实际类型。

引用对象的抽象类型

在很多情况下,一个Java 程序需要引用一个对象,如果一个被引用的对象存在抽象类型,就就当在任何引用此对象的地方,声明时使有抽象类型作为变量的静态类型,包括参量的类型声明,方法返还类型的声明。这就是针对接口编程的含义。

实现依赖倒转原则

以抽象方式耦合是依赖倒转原则的关键。由于一个抽象耦合关系总要涉及具体类从抽象类继承,并且需要保证在任何引用到基类的地方都可以改换在其子类,因此,里氏替换原则是依赖倒转原则的基础。

在抽象层次上的耦合虽然有灵活性,但也额外带来了复杂性。基某些情况下,如果一个具体类发生变化的可能性很小,那么抽象耦合能发挥的好处便十分有限,这时使用具体耦合反而会更好。

依赖倒转原则是 OO 设计的核心原则,设计模式的研究和应用是以依赖倒转原则为指导原则的。

模板方法模式

模板方法模式是依赖倒置原则的具体体现。在模板方法模式里面,有一个抽象类将得要的宏观逻辑以具体方法以及具体构造方法的形式实现,然后声明一些抽象方法来迫使子类实现剩余的具体细节上的逻辑。不同的子类可以以不同的方式实现这些抽象方法,而从对剩余的逻辑有不同的实现。

具体子类不能影响抽象类的达能观逻辑,而抽象逻辑的改变则会导致细节逻辑的改变。

迭代子模式

迭代子模式用一个工厂方法向客户端提供一个聚集的内部迭代功能,客户端得到的是一个Iterator 抽象类型,并不知道迭代子的具体实现以及聚集对象的内部结构。聚集的内部结构的改变就不会涉及到客户端,从而实现了对抽象接口的依赖。

更多内容请访问:IT源点

相关文章推荐

全部评论: 0

    我有话说: