胡桃仁

虚度光阴27 载

🔖🔖看韩顺平讲设计模式原则-依赖倒转原则,代码实践。

依赖倒转原则(dependence invertion principle)

  • 高层模块不应该依赖底层模块(类结继承类),二者都应该依赖其抽象(接口、抽象类)
  • 抽象不应该依赖细节,细节应该依赖抽象
  • 依赖倒转的中心思想是面向接口编程
  • 设计理念:高层模块多是接口或抽象类
  • 接口和抽象类的目的是制定规范,而不涉及具体的操作,把展现细节的任务交给他们的实现类去完成。

抛出问题

Person 接收消息的功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class DependencyInversion {
public static void main(String[] args) {
Person person = new Person();
person.receive(new Email());
}
}


class Email{
public String getInfo(){
return "发送邮件";
}
}
class Person{
public void receive(Email email) {
System.out.println(email.getInfo());
}
}

如果接受的消息是短信等类型的,则先要新增类似email的类,同时Person 类也要增加相应的接受方法。

解决思路

引入一个抽象的接口IReceiver,标识接收者,这样Person 类与接口发生依赖。
因为,email 和短信等等属于一个接收种类,他们各自实现IReceiver 接口就可以了,这样就符合依赖倒转原则(符合开始说的:细节应该依赖抽象)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class DependencyInversion {
public static void main(String[] args) {
// 客户端不用改变呢都
Person person = new Person();
person.receive(new Email());
}
}


interface IReceiver {
public String getInfo();
}


class Email implements IReceiver{
public String getInfo(){
return "发送邮件";
}
}
class Person{
public void receive(IReceiver receiver) {
System.out.println(receiver.getInfo());
}
}

现在添加接收短信消息的方式,该怎么办?
添加一个接受者接口,Person 类依赖接收者接口,使用的时候,接收哪种信息就创建哪种类去先实现接收者接口,再交给Person 类引用。

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
public class DependencyInversion {
public static void main(String[] args) {
// 客户端不用改变呢都
Person person = new Person();
person.receive(new Email());
// 接受短信
person.receive(new ShortMsg());
}
}
// 接收者接口
interface IReceiver {
public String getInfo();
}
// 接收短信的时候就创建接口类实现接收者接口
class ShortMsg implements IReceiver {
public String getInfo() {
return "";
}
}
// 接收邮件的时候就创建接口类实现接收者接口
class Email implements IReceiver{
public String getInfo(){
return "发送邮件";
}
}
class Person{
public void receive(IReceiver receiver) {
System.out.println(receiver.getInfo());
}
}

依赖关系传递的三种方式和应用案例

写新功能的时候可以对照实现的是play()方法

  • 接口传递
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
public class Example1 {
public static void main(String[] args) {
OpenAndClose openAndClose = new OpenAndClose();
openAndClose.open(new XiaoMiTV());
openAndClose.open(new SonyTv());
}
}

interface IOpenAndClose {
public void open(ITv tv);
}
interface ITv {
public void play();
}

class OpenAndClose implements IOpenAndClose {
public void open(ITv tv) {
tv.play();
}
}

//定义小米电视
class XiaoMiTV implements ITv {
public void play() {
System.out.println("播放小米电视");
}
}
// 定义索尼电视
class SonyTv implements ITv {
public void play() {
System.out.println("播放索尼电视");
}
}
  • 构造方法传递
    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
    public class Example2 {
    public static void main(String[] args) {
    OpenAndClose openAndClose = new OpenAndClose(new XiaoMiTV());
    openAndClose.open();

    OpenAndClose openAndClose1 = new OpenAndClose(new SonyTv());
    openAndClose1.open();
    }
    }

    interface IOpenAndClose {
    public void open();
    }
    interface ITv {
    public void play();
    }

    class OpenAndClose implements IOpenAndClose {
    private ITv tv;
    public OpenAndClose(ITv tv) {
    this.tv = tv;
    }

    public void open() {
    this.tv.play();
    }
    }

    //定义小米电视
    class XiaoMiTV implements ITv {
    public void play() {
    System.out.println("播放小米电视");
    }
    }
    // 定义索尼电视
    class SonyTv implements ITv {
    public void play() {
    System.out.println("播放索尼电视");
    }
    }
  • 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
    public class Example3 {
    public static void main(String[] args) {
    OpenAndClose openAndClose = new OpenAndClose();
    openAndClose.setTv(new XiaoMiTV());
    openAndClose.open();
    openAndClose.setTv(new SonyTv());
    openAndClose.open();
    }
    }

    interface IOpenAndClose {
    public void open();
    public void setTv(ITv tv);
    }
    interface ITv {
    public void play();
    }

    class OpenAndClose implements IOpenAndClose {
    private ITv tv;
    public void setTv(ITv tv) {
    this.tv = tv;
    }
    public void open() {
    this.tv.play();
    }
    }

    //定义小米电视
    class XiaoMiTV implements ITv {
    public void play() {
    System.out.println("播放小米电视");
    }
    }
    // 定义索尼电视
    class SonyTv implements ITv {
    public void play() {
    System.out.println("播放索尼电视");
    }
    }

    注意事项和细节

  • 底层模块尽量都要有抽象类或接口,或者两者都有
  • 变量的声明类尽量是抽象类或接口,这样我们的变量引用和实例对象间就存在一个缓冲层,利于程序的扩展和优化。
  • 继承时遵循里氏替换原则

评论