一、依赖倒转原则(Dependence Inversion Principle)特点
1、依赖倒转原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多.以抽象为基础搭建的架构比以细节为基础的架构要稳定的多.在 java 中,抽象指的是接口或抽象类,细节就是具体的实现类
2、高层模块不应该依赖低层模块,二者都应该依赖其抽象
3、抽象不应该依赖细节,细节应该依赖抽象
4、使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成
5、依赖倒转(倒置)的中心思想是面向接口编程
二、案例演示
完成 Person 接收消息的功能
方式一、普通实现
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() 方法,这样就比较麻烦.所以我们需要使用依赖倒置来改进
方式二、依赖倒置
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、接口传递
在接口的方法中声明依赖对象,该方法也叫做接口注入.
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、构造方法传递
在类中通过构造函数依赖对象,安装依赖注入的说法,这种方式叫做构造函数注入.
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 依赖注入
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、继承时遵循里氏替换原则