• 第2章 面向对象的设计原则(SOLID):3_依赖倒置原则(DIP)


    3. 依赖倒置原则(Dependence Inversion Principle,DIP)

    3.1 定义

    (1)要依赖抽象不要依赖具体的实现类。简单的说就是对抽象(或接口)进行编程,不要依赖实现进行编程,这样就降低了客户与实现模块间的耦合。包含3层含义:

      ①高层模块不应依赖低层模块,两者都应该依赖于抽象

      ②抽象不应该依赖细节

      ③细节应该依赖于抽象

    (2)何为“高层模块”和“低层模块”

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

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

    (3)何为“倒置”

      ①“依赖正置”:就是类间的依赖是实实在在的实现类间的依赖,也就是面向实现编程,这符合人的正常思维。如我们开奔驰车就是依赖奔驰车,使用笔记本电脑就直接依赖笔记本电脑。

      ②“依赖倒置”:编程是对现实世界事物进行抽象,然后我们根据系统设计的需要产生了对抽象的依赖,代替了人的传统思维中事物间的依赖,这叫“倒置”。

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

    (1)Driver只能开奔驰车!

     

    【编程实验】司机只能看奔驰车

    //面向对象设计原则:DIP依赖倒置原则
    //司机只能开奔驰车——依赖具体实现
    
    #include <stdio.h>
    
    //奔驰车类
    class Benz
    {
    public:
        void run()
        {
            printf("Benz Runing...
    ");
        }
    };
    
    //司机类
    class Driver
    {
    public:
        //司机类不是依赖于抽象,而是依赖具体的汽车Benz,
        //导致司机只能开奔驰,不能开其它车的尴尬!
        void drive(Benz& benz)
        {
            benz.run();
        }
     
    };
    
    int main()
    {
        Driver zhangSan;
        Benz benz;
        
        //张三开奔驰车
        zhangSan.drive(benz); //参数为Benz类型,张三只会开奔驰!
        
        return 0;
    }

    (2)解决方案——引入依赖倒置!

      ①通过IDriver和ICar两个接口来类间的耦合,引入依赖倒置原则

      ②汽车提供run方法。司机的职能就是驾驶汽车,必须实现Drive方法。当新增加汽车类时只要该汽车实现了ICar接口,司机就可以开了。

      ③Client是高层业务逻辑,它对低层的依赖是建立在抽象上。

     

    【编程实验】司机可开各类车

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

    3.3 依赖的3种写法(详见第1章)

    (1)构造函数传递依赖对象

    (2)Setter方法传递赖对象

    (3)通过接口声明依赖对象(如编程实验2)

    3.4 最佳实践

    (1)每个类尽量都有接口或抽象类,或两者都有,这是依赖倒置的基本要求,有了抽象才可能依赖倒置

    (2)声明变量时尽量用接口或抽象类,实例化再用具体的类

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

    (4)尽量不要覆盖基类己经实现的的方法。

    (5)结合里氏替换原则,对子类进行设计。以便实现类能准确的实现业务逻辑又不违反LSP原则。

  • 相关阅读:
    TabActivity 、fragemnt+fragment 和 Fragment+Viewpager 优缺点
    Android App的签名打包(晋级篇)
    Android ProgressBar 进度条荧光效果
    Android UI【android 仿微信、QQ聊天,带表情,可翻页,带翻页拖动缓冲】
    Android UI--自定义ListView(实现下拉刷新+加载更多)
    Android平台下利用zxing实现二维码开发
    自定义组件---图片和文字实现ImageButton效果
    JNI由浅入深_10_JNI 综合开发
    开关按钮实现
    Android Asynctask与Handler的比较,优缺点区别,Asynctask源码
  • 原文地址:https://www.cnblogs.com/5iedu/p/5475813.html
Copyright © 2020-2023  润新知