文章目录
一、定义
- 高层模块不应该依赖低层模块,二者都应该依赖它们的抽象
- 抽象不应该依赖细节,细节反而需要依赖抽象
- 依赖倒转的中心思想使是面向接口编程
- 依赖倒转原则所基于的设计理念 : 相较于细节的多变性,抽象的东西稳定的多;以抽象为基础的架构比以细节为基础的架构要稳定的多
- 在Java中,抽象指的是接口或抽象类,细节是具体的实现类
- 接口/抽象类的作用是制定规范,实现类的作用是展现细节
二、应用举例
我们使用一个 Person
类接收不同类型信息的例子来说明
2.1 方式一
class Email {
public String getMessage() {
return "电子邮件: " + "hello";
}
}
class Person {
public void receive(Email email) {
System.out.println(email.getMessage());
}
}
public class Client {
public static void main(String[] args) {
Person person = new Person();
person.receive(new Email());
}
}
运行结果:
- 这个方法可以解决我们的问题
- 但是如果我们想获取其它类型的信息(例如:QQ、微信),就得新增类,还得修改
Person
类,添加新的接收方法 - 所以,我们可以引入一个抽象的接口
IReceiver
来表示接收者,这样Person
类就可以和IReceive
接口产生依赖,而 Email、WeiXin 等各自实现接口IReceiver
就可以了,这样我们就符合依赖倒转原则了
2.2 方式二
// 接口IReceiveer表示接收者
interface IReceiver {
String getMessage();
}
class Email implements IReceiver {
public String getMessage() {
return "电子邮件: " + "hello";
}
}
class WeiXin implements IReceiver {
public String getMessage() {
return "微信: " + "hi";
}
}
// 这里对接口进行依赖
class Person {
public void receive(IReceiver receiver) {
System.out.println(receiver.getMessage());
}
}
public class Client {
public static void main(String[] args) {
Person person = new Person();
person.receive(new WeiXin());
}
}
运行结果:
- 通过添加一个接口
IReceiver
,再让所有类型的信息实现这个接口,我们的信息类型就可以不断地横向拓展了 - 同时,我们地客户端也不需要进行修改
三、依赖关系传递的三种方式
依赖关系的传递有三种方式,分别是接口传递、构造方法传递和 setter
方法传递
3.1 方式一:接口传递
请见上面 应用举例中的方式二
3.2 方式二:构造方法传递
interface IReceiver {
String getMessage();
}
class Email implements IReceiver {
public String getMessage() {
return "电子邮件: " + "hello";
}
}
class WeiXin implements IReceiver {
public String getMessage() {
return "微信: " + "hi";
}
}
class Person {
private IReceiver receiver;
public Person(IReceiver receiver) {
this.receiver = receiver;
}
public void receive() {
System.out.println(this.receiver.getMessage());
}
}
public class Client {
public static void main(String[] args) {
Person person1 = new Person(new Email());
person1.receive();
Person person2 = new Person(new WeiXin());
person2.receive();
}
}
3.3 方法三:setter方法传递
interface IReceiver {
String getMessage();
}
class Email implements IReceiver {
public String getMessage() {
return "电子邮件: " + "hello";
}
}
class WeiXin implements IReceiver {
public String getMessage() {
return "微信: " + "hi";
}
}
class Person {
private IReceiver receiver;
public void setReceiver(IReceiver receiver) {
this.receiver = receiver;
}
public void receive() {
System.out.println(this.receiver.getMessage());
}
}
public class Client {
public static void main(String[] args) {
Person person = new Person();
person.setReceiver(new Email());
person.receive();
person.setReceiver(new WeiXin());
person.receive();
}
}
四、注意事项和细节
- 低层模块尽量都要有抽象类或接口,或者两者都有
- 变量的声明类型尽量是抽象类或接口
- 继承时遵循里氏替换原则
- 依赖倒转的核心就是面向接口编程