第4章 依赖倒置原则(DIP)

来源:互联网 发布:1080j 最新x站免费域名 编辑:程序博客网 时间:2024/05/19 17:48

一、定义

1、模块间要依赖抽象,不要通过具体的实现类。依赖关系通过接口(抽象)进行编程,这就降低客户与实现模块间的耦

合。(接口或抽象类不依赖于实现类,实现类依赖接口或抽象类 面向接口编程OOD) 包含三层含义:

(1)高层模块不应依赖于低层模块,两者都应该依赖其抽象

(2)抽象不应该依赖细节  (3)细节应该依赖于抽象

2、高层模块和底层模块的概念

(1)低层模块:每个逻辑的实现都是原子逻辑组成,不可分割的原子逻辑就是低层模块。一般和具体的实现相关。

(2)高层模块:原子模块再组装就是高层模块,一般和业务逻辑相关。如客户端。

Java语言中,抽象就是指的是接口或抽象类,两者都不能直接被实例化。

        细节就是实现类,实现接口或继承抽象类而产生的类就是细节,特点是直接可以被实例化。

3、何为"倒置"

(1)、依赖正置:类间的依赖是实实在在的实现类间的依赖,面向实现编程,符合人类正常的思维。

(2)、依赖倒置:编程就是对现实世界事务进行抽象,然后根据系统设计产生对抽象的依赖,代替事物间的依赖,称

为"倒置"。

二、依赖实现编程存在的问题及改进

1、Driver只能开奔驰车!

   Client是场景类

实验:依赖于实现类,导致司机只能开奔驰车

//面向对象设计原则:DIP依赖倒置原则//司机只能开奔驰车——依赖具体实现#include <stdio.h>//奔驰车类class Benz{public:    void run()    {        printf("Benz Runing...\n");    }};//司机类class Driver{public:    //司机类不是依赖于抽象,而是依赖具体的汽车Benz,    //导致司机只能开奔驰,不能开其它车的尴尬!    void drive(Benz& benz)    {        benz.run();    } };int main(){    Driver zhangSan;    Benz benz;        //张三开奔驰车    zhangSan.drive(benz); //参数为Benz类型,张三只会开奔驰!        return 0;}
有车、有司机,在场景类产生相应的对象。到目前为止,这个司机开奔驰车的项目没有问题。但是业务需求变更永无

休止,技术前进就永无止境,在发生变更的时候才发觉我们设计的程序是否是松耦合。

现在呢,张三司机又想开宝马车,怎么实现呢?设计出现问题:司机类和奔驰车类之间是紧耦合的关系,导致的结果

就是系统的可维护性降低,可读性降低,稳定性低。

2、依赖倒置隆重登场

(1)、好处:减少类间耦合,提高系统的稳定性,提高代码的可维护性和可读性,降低并行开发引起的风险

(2)、通过IDriver和ICar两个接口来实现类间的耦合,引入依赖倒置原则。

接口只是一个抽象化的概念,是对一类事物抽象的描述,具体的代码由相应的实现类来实现。

(3)汽车提供run方法。司机的只能就是驾驶汽车,必须实现Driver方法。新增汽车类只需要实现ICar接口。

(4)ICar接口实现抽象之间的依赖关系,Driver实现类也传入ICar接口,到底是那个Car,需要在高层模块声明。

(5)业务场景类中,抽象不应该依赖细节,也就是抽象(接口)不依赖于实现类(细节),高层模块应用的都是抽象。

     

编程:司机可以开各种车

//面向对象设计原则:DIP依赖倒置原则//司机可开任何汽车——依赖抽象/接口#include <stdio.h>//汽车接口class ICar{public:    virtual void run() = 0;};//奔驰车类class Benz : public ICar{public:    void run(){printf("Benz runing...\n");}};//宝马车类class BWM : public ICar{public:    void run(){printf("BWM runing...\n");}};//司机接口class IDriver{public:    //是司机应该会驾驶汽车    virtual void drive(ICar& car) = 0; //依赖接口};//司机类class Driver : public IDriver{public:    void drive(ICar& car) //实现接口    {        car.run();    }};int main(){    Driver zhangSan;  //引用(对象)   指针(new)    Benz benz;    BWM  bwm;        //张三开奔驰车    zhangSan.drive(benz);         //张三开宝马    zhangSan.drive(bwm);        return 0;}

Client属于高层业务逻辑,对低层的依赖都建立在抽象上,zhangsan都是以IDriver类型进行操作,屏蔽了细节对抽

象的影响。java中,一个变量可以有两种类型:表面类型和实际类型,表面类型是定义的时候赋予的类型,实际类型

是对象的类型。如zhangsan的表面类型是IDriver,实际类型是Driver。

三、依赖的3种写法

1、构造函数传递依赖对象


2、setter方法传递依赖对象


3、通过接口声明依赖对象(接口注入)


四、最佳实践

依赖倒置原则的本质就是通过抽象(抽象类或接口)使各个类或者模块的实现彼此独立,不相互影响,实现模块间的松

耦合。

1、每个类尽量都有接口或者抽象类,或者两者都有,有了抽象才能依赖倒置

2、声明变量时尽量用接口或抽象类,实例化再使用具体的类。变量的表面类型尽量是接口或者抽象类

3、任何类都不应该从具体的类派生(或者继承具体的类不超过两层)

4、尽量不要覆写基类已经实现的方法。如果基类是抽象类,而且这个方法已经实现了,子类尽量不要覆写。类间依

赖的是抽象,覆写抽象方法,对依赖的稳定性产生影响。

5、结合里氏替换原则对子类进行设计。

接口负责定义public属性和方法,并且声明与其他对象的依赖关系。

抽象类负责公共构造部分的实现,实现类准确的实现业务逻辑,同时在适当的时候对父类进行细化。

"面向接口编程"基本上是依赖倒置原则的核心。

0 0
原创粉丝点击