zoukankan      html  css  js  c++  java
  • 03.依赖倒置原则 (DIP)

    DIP全称

    DIP, Dependence Inversion Principle , 依赖倒置原则

    定义

    模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口和抽象类产生的。

    面向接口编程,或者说是面向抽象编程。依赖抽象(接口或者抽象类),而不依赖具体实现。高层次(调用端)的模块不依赖于低层次(实现类)的模块的实现细节。

    优点

    1. 降低类之间的耦合性
    2. 提高系统的稳定性
    3. 降低修改程序造成的风险

    实现

    • 问题由来: 类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。

    • 解决方案:
      将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率。
      以抽象方式耦合是依赖倒转原则的关键。抽象耦合关系总要涉及具体类从抽象类继承,并且需要保证在任何引用到基类的地方都可以改换成其子类,因此,里氏代换原则是依赖倒转原则的基础。

    实例

    场景:母亲给孩子讲故事,只要给她一本书,她就可以照着书给孩子讲故事了。

    class Book {
        public String getContent() {
            return "很久很久以前......";
        }
    }
    
    class Monther {
        public void narrate(Book book) {
            System.out.println("妈妈开始讲故事");
            System.out.println(book.getContent());
        }
    }
    
    public class DIPClient {
        public static void main(String[] args) {
            Monther monther = new Monther();
            monther.narrate(new Book());
        }
    }
    
    输出结果:
    妈妈开始讲故事
    很久很久以前......
    

    如果此时需要讲报纸上的内容,就需要再新建一个类Newspaper

    class Newspaper {
        public String getContent() {
            return "金融风暴卷土而来......";
        }
    }
    
    class Book {
        public String getContent() {
            return "很久很久以前......";
        }
    }
    
    class Monther {
        public void narrate(Book book) {
            System.out.println("妈妈开始讲书上的故事");
            System.out.println(book.getContent());
        }
    
        public void narrate(Newspaper newspaper) {
            System.out.println("妈妈开始讲报纸上的内容");
            System.out.println(newspaper.getContent());
        }
    }
    
    public class DIPClient {
        public static void main(String[] args) {
            Monther monther = new Monther();
            monther.narrate(new Book());
    
            monther.narrate(new Newspaper());
        }
    }
    
    输出结果:
    妈妈开始讲书上的故事
    很久很久以前......
    妈妈开始讲报纸上的内容
    金融风暴卷土而来......
    

    如果再来个讲头条的内容,又要新建一个类,然后改动Monther类,这样做不太合理。此时新建接口类,使其依赖于接口,而不是具体实现类,达到Monther类不用修改的目的。

    interface IReader {
        String getContent();
    }
    
    class Newspaper implements IReader {
        @Override
        public String getContent() {
            System.out.println("妈妈开始讲报纸上的内容");
            return "金融风暴卷土而来......";
        }
    }
    
    class Book implements IReader {
        @Override
        public String getContent() {
            System.out.println("妈妈开始讲书上的故事");
            return "很久很久以前......";
        }
    }
    
    class Monther {
        public void narrate(IReader reader) {
            System.out.println(reader.getContent());
        }
    }
    
    public class DIPClient {
        public static void main(String[] args) {
            Monther monther = new Monther();
            monther.narrate(new Book());
            monther.narrate(new Newspaper());
        }
    }
    
    输出结果:
    妈妈开始讲书上的故事
    很久很久以前......
    妈妈开始讲报纸上的内容
    金融风暴卷土而来......
    

    Mother类与接口IReader发生依赖关系,而Book和Newspaper都属于读物的范畴,他们各自都去实现IReader接口,这样就符合依赖倒置原则了。

    传递依赖关系有三种方式,以上的例子中使用的方法是接口传递,另外还有两种传递方式:构造方法传递和setter方法传递。

    在实际编程中,我们一般需要做到如下3点:

    1. 低层模块尽量都要有抽象类或接口,或者两者都有。
    2. 变量的声明类型尽量是抽象类或接口。
    3. 使用继承时遵循里氏替换原则。
  • 相关阅读:
    git 专题
    Android yyyymmdd转成yyyy-MM-dd格式
    Android LayoutInflater.from(context).inflate
    Android TextView内容过长加省略号,点击显示全部内容
    Android 标题栏封装
    Android 自定义Android带图片和文字的ImageButton
    Android 防止按钮连续点击的方法(Button,ImageButton等)
    Android 动态改变布局属性RelativeLayout.LayoutParams.addRule()
    Android ActionBar的Overlay模式如何不遮盖顶部内容的问题
    Android 时间轴TimeLine
  • 原文地址:https://www.cnblogs.com/lwcode6/p/13954925.html
Copyright © 2011-2022 走看看