设计模式七大原则03---依赖倒转原则

一、依赖倒转原则(Dependence Inversion Principle)特点

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

2、高层模块不应该依赖低层模块,二者都应该依赖其抽象

3、抽象不应该依赖细节,细节应该依赖抽象

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

5、依赖倒转(倒置)的中心思想是面向接口编程

 

二、案例演示

完成 Person 接收消息的功能

方式一、普通实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class DesignPatternPrinciple {
    public static void main(String[] args) {
        Person person = new Person();
        person.receiveMessage(new Email());
    }
}
 
class Person{
    public void receiveMessage(Email email){
        email.receive();
    }
}
 
class Email {
    public void receive(){
        System.out.println("接收 email 信息");
    }
}

上面的代码已经完成了我们的需求,但是存在一个问题,我们 Person 类里面的 receiveMessage(Email email) 方法参数类型是 Email 类型的,它代表的意思是只能接收 Email 类型的消息,如果我这个时候想接收微信消息、QQ 消息,那么就要继续重写 receiveMessage() 方法,这样就比较麻烦.所以我们需要使用依赖倒置来改进

方式二、依赖倒置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class DesignPatternPrinciple {
    public static void main(String[] args) {
        Person person = new Person();
        person.receiveMessage(new Email());
        person.receiveMessage(new Wechat());
        person.receiveMessage(new QQ());
    }
}
 
interface Message {
    public abstract void receive();
}
 
class Person {
    public void receiveMessage(Message message) {
        message.receive();
    }
}
 
class Email implements Message {
    public void receive() {
        System.out.println("接收 email 信息");
    }
}
 
class Wechat implements Message {
    public void receive() {
        System.out.println("接收 wechat 信息");
    }
}
 
class QQ implements Message {
    public void receive() {
        System.out.println("接收 qq 信息");
    }
}

使用依赖倒置改进之后,扩展起来也比较方便了.

 

三、依赖关系传递的三种方式

依赖是可以传递的,A对象依赖B对象,B对象又依赖C对象,C对象又依赖D对象......生生不息,依赖不止.要记住一点:只要做到抽象依赖,即使多层的依赖传递也无所畏惧.对象的依赖关系主要有三种方式来传递.

1、接口传递

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class DesignPatternPrinciple {
    public static void main(String[] args) {
        Idriver idriver = new Driver();
        idriver.drive(new Benz());
        idriver.drive(new Porsche());
    }
}
 
interface Icar {
    public void run();
}
 
interface Idriver {
    public void drive(Icar icar);
}
 
class Benz implements Icar {
    @Override
    public void run() {
        System.out.println("Benz run...");
    }
}
 
class Porsche implements Icar {
    @Override
    public void run() {
        System.out.println("Porsche run...");
    }
}
 
class Driver implements Idriver {
    @Override
    public void drive(Icar icar) {
        icar.run();
    }
}

2、构造方法传递

在类中通过构造函数依赖对象,安装依赖注入的说法,这种方式叫做构造函数注入.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class DesignPatternPrinciple {
    public static void main(String[] args) {
        Idriver benz = new Driver(new Benz());
        benz.drive();
        Idriver porsche = new Driver(new Porsche());
        porsche.drive();
    }
}
 
interface Icar {
    public void run();
}
 
interface Idriver {
    public void drive();
}
 
class Benz implements Icar {
    @Override
    public void run() {
        System.out.println("Benz run...");
    }
}
 
class Porsche implements Icar {
    @Override
    public void run() {
        System.out.println("Porsche run...");
    }
}
 
class Driver implements Idriver {
    private Icar icar;
 
    public Driver(Icar icar){
        this.icar = icar;
    }
 
    @Override
    public void drive() {
        icar.run();
    }
}

3、setter 方法传递

在抽象中设置 setter 方法声明依赖关系,依照依赖注入的说法.这个是 setter 依赖注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class DesignPatternPrinciple {
    public static void main(String[] args) {
        Driver benzDriver = new Driver();
        benzDriver.setIcar(new Benz());
        benzDriver.drive();
 
        Driver PorsDriver = new Driver();
        PorsDriver.setIcar(new Porsche());
        PorsDriver.drive();
    }
}
 
interface Icar {
    public void run();
}
 
interface Idriver {
    public void drive();
}
 
class Benz implements Icar {
    @Override
    public void run() {
        System.out.println("Benz run...");
    }
}
 
class Porsche implements Icar {
    @Override
    public void run() {
        System.out.println("Porsche run...");
    }
}
 
class Driver implements Idriver {
    private Icar icar;
 
    public void setIcar(Icar icar) {
        this.icar = icar;
    }
 
    @Override
    public void drive() {
        icar.run();
    }
}

  

四、依赖倒置注意事项

1、低层模块尽量都要有抽象类或接口,或者两者都有,程序稳定性更好

2、变量的声明类型尽量是抽象类或接口,,这样我们的变量引用和实际对象间,就存在一个缓冲层,利于程序扩展和优化

3、继承时遵循里氏替换原则

 

posted @   变体精灵  阅读(156)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示