设计模式六大原则:依赖倒置原则、为什么、多例子、分析例子、总结

本文详细介绍了设计模式中的依赖倒置原则,解释了为何需要倒转依赖,并给出了多个实例说明如何通过接口或抽象类实现这一原则。内容包括依赖倒置的定义、原因、实现方式以及遵循原则的经验分享。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 依赖倒置原则的定义

  1. 高层模块不应该依赖低层模块,二者都应该依赖其抽象
  2. 抽象不应该依赖细节,细节应该依赖抽象
  3. 依赖倒转的中心思想是面向接口编程
  4. 依赖倒转原则是基于这样的设计理念: 相对于细节的多变性,抽象的东西要稳定的多,以抽象为基础搭建的框架比以细节的框架要稳定的多。在JAVA、C#中,抽象指的是接口或者抽象类,细节就是具体的实现类。
  5. 使用接口或抽象类的目的是指定好的规范,而不涉及任何的具体操作,把展现细节的任务交给他们的实现类去完成。

总之,高层模块,低层模块,细节都应该依赖抽象

依赖倒置具体表现为:

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

2. 为什么是倒转?

一般来说,我们经常为了图方便,把具体类依赖于具体类,也就是所谓的高层模块依赖于低层模块,但是这样是不利于扩展的,违反了设计原则,此时:
在这里插入图片描述
而现在根据依赖倒置原则,我们需要将高层模块和低层模块都依赖于接口(或者抽象类)来实现

在这里插入图片描述
这里发生了倒置,本来是高层模块依赖于低层模块,低层模块被高层模块依赖,现在是低层模块主动依赖于接口,所以发生了倒置,所以这个原则也称为依赖倒置原则

3. 举例

3.1 第一个例子

摘自于:https://blog.csdn.net/weixin_37505014/article/details/94869450

现在要完成一个Person类接收消息的需求;
方式1:

public class Inversion01 {
    public static void main(String[] args) {
        Person person = new Person();
        person.receive(new Email());
    }
}
// 完成Person接收消息的功能
class Email {
    public String getInfo() {
        return "电子邮件信息: HELLO WORLD";
    }
}

class Person {
    public void receive(Email email) {
        System.out.println(email.getInfo());
    }
}

输出结果:电子邮件信息: HELLO WORLD

这里面Email就是低层模块,而Person是高层模块,高层模块依赖于低层模块,不符合依赖倒置原则,Person类智能接受Email类而不可以接受其他类,要改的话就要每次改代码

该方式很简单的实现了需求,但是有一些问题,我们现在接收的是邮件,如果将来需求变更需要再加上一个可以接收短信的功能,那么我们就需要新增类。同时,Person类也要增加相应的接收方法。

改进:
解决思路,引入一个抽象接口Reveiver,表示接收者,这样Person类与接口发生依赖。因为Email, 短信都属于接收范围,它们各自实现Receiver接口就行了,这样我们就符合依赖倒转原则。

public class Inversion02 {
    public static void main(String[] args) {
        Person02 person02 = new Person02();
        person02.receive(new Email02());
        person02.receive(new Message());
    }
}
//先定义一个接口
interface Receiver {
    String getInfo();
}

class Email02 implements Receiver {
    public String getInfo() {
        return "电子邮件信息: HELLO WORLD";
    }
}
//增加短信
class Message implements Receiver {
    public String getInfo() {
        return "短信信息: HELLO WORLD";
    }
}

class Person02 {
	//  这里我们是对接口的依赖,稳定性较好
    public void receive(Receiver receiver) {
        System.out.println(receiver.getInfo());
    }
}

输出结果:电子邮件信息: HELLO WORLD,短信信息: HELLO WORLD

此时,高层模块(Person)和低层模块(Email和Message)都依赖于接口(Receive),符合依赖倒置原则

3.2 第二个例子

摘自:
https://blog.csdn.net/hfreeman2008/article/details/52289571?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control

这个例子里面有个图画错了,IReader和IRead的指向反了,其他没问题

4. 依赖的三种方法

4.1 构造函数传递依赖对象

在类中通过构造函数声明依赖对象,按照依赖注入的说法,这种方式叫做构造函数注入:

构造函数注入:

//小明类
public class XiaoMing implements IReader{
     private IRead read;
     //构造函数注入
     public XiaoMing(IRead read){
        this.read = read;
     }

    //阅读
    public void read(){
        read.read();
    }
}

4.2 Setter方法传递依赖对象

在类中通过Setter方法声明依赖关系,依照依赖注入的说法,这是Setter依赖注入:

//小明类
public class XiaoMing implements IReader{
     private IRead read;
     //Setter依赖注入
     public setRead(IRead read){
        this.read = read;
     }

    //阅读
    public void read(){
        read.read();
    }
}

4.3 接口声明依赖

在接口的方法中声明依赖对象,该方法也叫做接口注入。

public interface IReader{
   //阅读
   public void read(IRead read){
       read.read();
   }
}
//IReader接口依赖于IRead 接口

5. 依赖倒置原则的经验

依赖倒置原则的本质就是通过抽象(接口或抽象类)使各个类或模块的实现彼此独立,不互相影响,实现模块间的松耦合。我们在项目中使用这个原则要遵循下面的规则:

  • 每个类尽量都有接口或者抽象类,或者抽象类和接口两都具备
  • 变量的表面类型尽量是接口或者抽象类
  • 任何类都不应该从具体类派生
  • 尽量不要覆写基类的方法
  • 如果基类是一个抽象类,而这个方法已经实现了,子类尽量不要覆写。类间依赖的是抽象,覆写了抽象方法,对依赖的稳定性会有一定的影响。

结合里氏替换原则使用

里氏替换原则:父类出现的地方子类就能出现。结合本章我们得出了一个通俗的规则:接口负责定义public属性和方法,并且声明与其他对象的依赖关系。抽象类负责公共构造部分的实现,实现类准确的实现业务逻辑,同时在适当的时候对父类进行细化。

依赖倒置原则是6个设计原则中最难以实现的原则,它是实现开闭原则的重要方法,在项目中,大家只要记住是”面向接口编程”就基本上是抓住了依赖倒置原则的核心了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值