设计模式六大原则之----依赖倒置原则

前端之家收集整理的这篇文章主要介绍了设计模式六大原则之----依赖倒置原则前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

一、定义

高层模块不应该依赖于底层模块,二者都应该依赖其抽象,抽象不应该依赖细节,细节应该依赖抽象。

  • 抽象就是接口和抽象类;细节就是具体的实现类
  • 依赖倒置本质:通过抽象即接口或者抽象类,使各个类和模块间彼此独立,实现模块间的松耦合

友情提醒:xmind导出的图片有点模糊,请放大查看

二、 问题的由来

2.1 问题

类A直接依赖类B,假如要将类A改为依赖类C,那么必须修改类A来完成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是底层模块,负责基本的原子操作;修改类A有可能给程序带来不必要的风险。

2.2 解决方

将类A修改为依赖接口I,让类B和类C各自实现接口I,类A通过接口I间接与类B和类C发生关系,这样就会大大降低类A修改的几率。

三、 优点

  • 减少类之间的耦合
  • 提高系统的稳定性
  • 降低并发风险
  • 提高代码的可读性

四、 依赖倒置注入的实现

  • 构造函数注入依赖对象
    • 通过构造函数参数声明依赖对象
  • Setter方法注入依赖对象
    • 通过Setter方法参数声明依赖对象
  • 接口注入依赖对象
    • 通过接口参数声明依赖对象

五、 注意

抽象类中已经实现的方法,子类最好不要覆盖

六、 使用场景

  • 依赖倒置在小项目中很难体现出来,是否遵循依赖倒置原则影响不大
  • 项目越大,需求改变越多,采用依赖倒置原则设计的接口或者抽象类约束实现类,维护成本会大大减少

七、 案例

妈妈讲故事,用代码描述出来。

7.1 实现需求

母亲类:

public class Mother {
    private static final String TAG = "Mother";
    public Book book;

    public Mother(Book book) {
        this.book = book;
    }

    public void tellStory(){
        Log.e(TAG,"妈妈讲故事:"+book.getContent());
    }
}

Book类:

public class Book {

    public String getContent() {
        return "白雪公主和七个小矮人的故事";
    }
}

客户端调用

Book book = new Book();
    Mother mother = new Mother(book);
    mother.tellStory();

执行结果:

11-15 17:07:24.718 17891-17891/com.designpatterndisclipline E/Mother: 妈妈讲故事:白雪公主和七个小矮人的故事

7.2 增加需求

母亲不光能够读书,还能够读报纸

添加一个报纸类

public class NewsPaper {
    public String getContent() {
        return "今年的双十一又突破了几千亿了...";
    }
}

修改母亲类中的逻辑,让他能够读报纸

/**
 * Created by rytong on 2017/11/15.
 */

public class Mother {
    private static final String TAG = "Mother";
    private Book book;
    private NewsPaper newsPaper;

    public void setBook(Book book) {
        this.book = book;
    }

    public void setNewsPaper(NewsPaper newsPaper) {
        this.newsPaper = newsPaper;
    }

    public void ReadBook(){
        Log.e(TAG,"妈妈讲故事:"+book.getContent());
    }

    public void ReadNewsPaper(){
        Log.e(TAG,"妈妈读报纸:"+newsPaper.getContent());
    }
}

修改客户端调用逻辑:

Mother mother = new Mother();
    mother.setBook(new Book());
    mother.setNewsPaper(new NewsPaper());

    mother.ReadBook();
    mother.ReadNewsPaper();

执行结果:

11-15 17:16:00.568 23141-23141/? E/Mother: 妈妈讲故事:白雪公主和七个小矮人的故事
11-15 17:16:00.568 23141-23141/? E/Mother: 妈妈读报纸:今年的双十一又突破了几千亿了...

在刚才的代码中,我们添加了新的新闻类,修改了Mother类,修改了客户端调用的地方。其中Mother类的修改有可能会影响之前读书的逻辑,是有隐患的。

7.3 遵循依赖倒置原则重构

让书、报纸等读物实现同一个接口

/**
 * Created by rytong on 2017/11/15.
 */

public interface IBook {
    public String getContent();
}

报纸和故事书都实现该接口

public class Book implements IBook{

    public String getContent() {
        return "白雪公主和七个小矮人的故事";
    }
}

public class NewsPaper implements IBook{
    public String getContent() {
        return "今年的双十一又突破了几千亿了...";
    }
}

修改母亲类中的逻辑

public class Mother {
    private static final String TAG = "Mother";
    private IBook iBook;

    public void setiBook(IBook iBook) {
        this.iBook = iBook;
    }
    public void read(){
        if (iBook instanceof Book){
            Log.e(TAG,"妈妈讲故事:"+iBook.getContent());
        }
        if (iBook instanceof NewsPaper){
            Log.e(TAG,"妈妈读报纸:"+iBook.getContent());
        }
    }
}

客户端调用

Mother mother = new Mother();
    IBook iBook = new Book();
    mother.setiBook(iBook);
    mother.read();

    iBook = new NewsPaper();
    mother.setiBook(iBook);
    mother.read();

执行结果:

11-15 17:32:17.890 32436-32436/com.designpatterndisclipline E/Mother: 妈妈讲故事:白雪公主和七个小矮人的故事
11-15 17:32:17.891 32436-32436/com.designpatterndisclipline E/Mother: 妈妈读报纸:今年的双十一又突破了几千亿了...

这里这个简单的例子,简单的模仿了新需求增加时的一些逻辑处理,本例子也并没有完全遵循依赖倒置原则,在Mother中每次修改还需要加小部分逻辑,不过比之前已经好了很多了。需要注意一点:如果方法在抽象类中已经实现,子类尽量不要覆盖该方法

猜你在找的设计模式相关文章