第4节 依赖倒转原则
4.1 基本介绍
- 高层模块不应该依赖低层模块,二者都应该依赖其抽象层。低层模块尽量都要有抽象类或者接口,即,类 A 是一个子类,其上面应该都有接口。例如,在 Java 中,抽象指的是接口或抽象类,细节就是具体的实现类
- 依赖倒转的核心思想是面向接口编程,
- 抽象不应该依赖细节,细节应该依赖抽象
- 使用接口或抽象的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给它们的实现类去完成
- 依赖倒转的理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础的架构要稳定的多
- 继承时应该遵循里氏替换原则(下一节会介绍里式替换原则)
4.2 需求介绍
完成 Person 接收消息的功能
4.3 传统写法
/**
* demo:不使用依赖倒转原则
*/
public class Client {
public static void main(String[] args) {
Person person = new Person();
person.receive(new Email());
}
}
class Email {
public String getInfo() {
return "[电子邮件] hello world";
}
}
/**
* 完成 Person 接收电子邮件的功能
*/
class Person {
public void receive(Email email) {
System.out.println(email.getInfo());
}
}
问题:receive()方法的参数是 Email,即,直接依赖了一个具体的类。如果现在获取的对象是「微信」、「短信」等,就需要新增类,而且也需要修改(重写/重载)Person 中的 receive() 方法
4.4 解决方案
引入一个抽象的接口 IReceiver(表示接收者),这样 Person 类与接口 IReceiver 发生依赖。因为 Email、Weixin 等属于接收者的范围,它们各自实现 IReceiver 接口就行,这样就符合依赖倒转原则
public class Client {
public static void main(String[] args) {
Person person = new Person();
person.receive(new Email());
person.receive(new Wechat());
}
}
// 定义接口
interface IReceiver {
String getInfo();
}
class Email implements IReceiver {
@NonNull
public String getInfo() {
return "[电子邮件] hello Email";
}
}
// 增加微信消息
class Wechat implements IReceiver {
public String getInfo() {
return "[微信] hello Wechat";
}
}
class Person {
// receive 方法依赖接口
public void receive(IReceiver receiver) {
System.out.println(receiver.getInfo());
}
}
4.4 依赖的传递方式
- 通过接口实现依赖的传递
- 通过构造方法实现依赖的传递
- 通过 Setter 方法实现依赖的传递