寂然解读设计模式 - 依赖倒置原则

简介: 依赖倒置原则的核心就是面向抽象(抽象类或者接口)编程,大家要明白,以抽象为基准搭建起来的架构比以细节为基准搭建的架构要稳定的多,因此,在拿到需求之后,要先顶层再细节的方式来进行代码设计
I walk very slowly, but I never walk backwards 

设计模式原则 - 依赖倒转原则


寂然

大家好,我是寂然~,本节课呢,我来给大家介绍设计模式原则之依赖倒转原则,话不多说,我们直接进入正题,老规矩,首先带大家了解一下依赖倒转原则的官方定义,并作一个解释,然后我们通过案例代码来具体分析

官方定义

依赖倒转原则,又称依赖倒置原则(Dependence Inversion Principle),又称DIP原则,官方定义为:

High level modules should not depend upon low level modules. Both should depend upon abstractions.

(上层模块不应该依赖底层模块,它们都应该依赖于抽象)

Abstractions should not depend upon details. Details should depend upon abstractions.

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

基本介绍

依赖倒转原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多,以抽象为基础搭建的架构要比以细节为基础的架构稳定的多,在Java中,抽象指的是接口或抽象类,细节指具体的实现类,即要求程序要依赖于抽象接口,不要依赖于具体实现


使用接口或者抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成

换句话说,接口或者抽象类的价值就在于设计

案例演示 - 钉钉消息

OK,那我们假设有这样一个场景,有一个工作人员,每天要接收钉钉工作消息,简易代码如下图所示

//工作人员
class Worker {
    public void getMessage(Dingding dingding){
        dingding.sendMessage();
    }
}
//钉钉类
class Dingding{
    public void sendMessage(){
        System.out.println("钉钉上老板喊你加班呢");
    }
}
//测试代码
public class InversionDemo{
    public static void main(String[] args) {
        new Worker().getMessage(new Dingding());
    }
}

案例分析

OK,可以看到上面的代码,对案例场景进行了简易的实现,那我们就对上面的代码进行分析

现在是获取钉钉消息,如果我们获取的对象是微信,短信等,那根据上面的实现,我们需要新增类,同时Worker类也要增加相应的接收方法,这样显然维护性很差的同时,频繁修改代码也会带来意想不到的风险


那我们就想到了上面依赖倒转原则的定义,既然接口或者抽象类的价值就在于设计,我们可以引入一个接口来指定规范,表示信息的接收者,因为微信,钉钉都属于消息接收的途径,那就可以让他们实现该接口,来完成具体的细节,然后Worker与该接口发生依赖,使用依赖倒转的思想,完成代码改造

解决方案

OK,那根据上面的思路,我们对案例代码进行改造,改造后的代码示例如下:

//定义接口,指定接收消息的规范
interface IMessage{
    public void sendMassage();
}
//钉钉消息
class Dingding implements IMessage{
    @Override
    public void sendMassage() {
        System.out.println("钉钉上老板喊你开会啦");
    }
}
//微信消息
class Weixin implements IMessage{
    @Override
    public void sendMassage() {
        System.out.println("微信上老板喊你加班啦");
    }
}
//工作人员
class Worker {
    //这里是我们对于接口的依赖
    public void getMessage(IMessage message){
        message.sendMassage();
    }
}
//简易测试代码
public class Inversion01Demo{
    public static void main(String[] args) {
        new Worker().getMessage(new Dingding());
        new Worker().getMessage(new Weixin());
    }
}

案例总结

可以看到,通过上面改造过的代码,我们定义了接口作为模板,让各种消息接收的途径去实现,这样的话如果业务要求还需要接收短信的消息,添加短信类实现接口即可,工作人员端不需要进行变动和维护,其实依赖倒置原则的本质上就是通过抽象(抽象类或接口)使各个类或模块实现彼此独立,不互相影响,实现模块间的松耦合

一句话:依赖倒置原则的核心就是面向抽象(抽象类或者接口)编程,大家要明白,以抽象为基准搭建起来的架构比以细节为基准搭建的架构要稳定的多,因此,在拿到需求之后,要先顶层再细节的方式来进行代码设计

依赖关系传递方式

当我们进行依赖倒转的时候,一定要进行依赖关系的传递,接着,我们简单聊聊依赖关系的三种传递方式

一、通过接口传递

使用接口传递,示例代码如下

//通过接口方式传递
interface IMessage{
    public void sendMassage(Produce produce); //抽象方法,接收接口
}

interface Produce{
    void produceMessage();
}

//工作人员
class Worker implements IMessage{

    @Override
    public void sendMassage(Produce produce) {
        produce.produceMessage();
    }
}

可以看到,Worker实现了接口 IMessage,实现了里面的方法,该方法参数接收了 Produce 接口类型,这就是一个典型的使用接口传递的案例,抽象方法sendMassage() 里面传的是一个接口

二、通过构造方法传递

使用构造方法传递,示例代码如下

//通过构造器方式传递
interface IMessage{
    public void sendMassage(); //这里没有接收接口
}

interface Produce{
    void produceMessage();
}

class Worker implements IMessage{

    public Produce produce; //属性为Produce类型

    public Worker(Produce produce) { //构造器来传递
        this.produce = produce;
    }

    @Override
    public void sendMassage() {
        this.produce.produceMessage();
    }

}

可以看到,这种方式,将Produce置为 Worker类的属性,值通过构造器来传递,赋给 this.produce ,然后在sendMassage()方法里通过 this.produce 来调用目标方法

三、通过setter()方法传递

使用setter()方法传递,实例代码如下

//通过setter方式传递
interface IMessage{
    public void sendMassage();
}

interface Produce{
    void produceMessage();
}

class Worker implements IMessage{

    public Produce produce; //属性为Produce类型

    public void setProduce(Produce produce) {
        this.produce = produce;
    }

    @Override
    public void sendMassage() {
        this.produce.produceMessage();
    }
}

可以看到,这种方式,将Produce置为 Worker类的属性,值通过setter()方法来传递,赋给 this.produce ,然后在sendMassage()方法里通过 this.produce 来调用目标方法produceMessage()

注意事项&细节

  • 低层模块尽量都要有抽象类或接口,或者两者都有,程序稳定性更好
  • 变量的声明类型尽量是抽象类或者接口,这样我们的变量引用和实际对象间,就存在一个缓冲层,利于程序扩展和优化
  • 继承时遵循里式替换原则(下章内容来详细介绍)

下节预告

OK,下一节,我们正式进入设计模式原则之里式替换原则的学习,我会为大家用多个案例分析,来解读设计模式原则之里式替换原则,以及它的注意事项和细节,最后,希望大家在学习的过程中,能够感觉到设计模式的有趣之处,高效而愉快的学习,那我们下期见~

相关文章
|
5月前
|
设计模式
设计模式六大原则之依赖倒置原则
设计模式六大原则之依赖倒置原则
|
6月前
|
设计模式 Java
Java设计模式七大原则之依赖倒置原则
Java设计模式七大原则之依赖倒置原则
69 0
|
设计模式 uml
设计模式-浅谈依赖倒置原则
设计模式-浅谈依赖倒置原则
|
设计模式 Java Spring
【设计模式】依赖倒置原则与工厂方法模式与spring
【设计模式】依赖倒置原则与工厂方法模式与spring
118 0
|
设计模式 测试技术
设计模式 - 六大设计原则之DIP(依赖倒置原则)
设计代码架构时,高层模块不应该依赖于底层模块,二者都应该依赖于抽象。 抽象不应该依赖于细节,细节应该依赖于抽象。 依赖倒置原则是实现开闭原则的重要途径之一, 它降低了类之间的耦合,提高了系统的稳定性和可维护性。
145 0
设计模式 - 六大设计原则之DIP(依赖倒置原则)
|
设计模式
【设计模式】软件设计七大原则 ( 依赖倒置原则 | 代码示例 )(三)
【设计模式】软件设计七大原则 ( 依赖倒置原则 | 代码示例 )(三)
113 0
【设计模式】软件设计七大原则 ( 依赖倒置原则 | 代码示例 )(三)
|
设计模式 Java
设计模式—— 三:依赖倒置原则
设计模式—— 三:依赖倒置原则
238 0
设计模式—— 三:依赖倒置原则
|
设计模式 Java uml
设计模式六大原则(三)----依赖倒置原则
设计模式六大原则(三)----依赖倒置原则
139 0
|
存储 设计模式 数据库
大话设计模式--第五章 依赖倒置原则
依赖倒置原则: 原话解释的是, 抽象不应该依赖于细节, 细节应该依赖于抽象. 说白了, 就是上面那句话。针对接口编程, 不要针对实现编程。
99 0
|
设计模式
【设计模式】软件设计七大原则 ( 依赖倒置原则 | 代码示例 )(二)
【设计模式】软件设计七大原则 ( 依赖倒置原则 | 代码示例 )(二)
129 0

热门文章

最新文章

  • 1
    C++一分钟之-设计模式:工厂模式与抽象工厂
    43
  • 2
    《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
    49
  • 3
    C++一分钟之-C++中的设计模式:单例模式
    58
  • 4
    《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
    38
  • 5
    《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
    63
  • 6
    Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
    58
  • 7
    Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
    42
  • 8
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    50
  • 9
    Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
    110
  • 10
    Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
    78
  • 下一篇
    无影云桌面