总之,高层模块,低层模块,细节都应该依赖抽象
依赖倒置具体表现为:
一般来说,我们经常为了图方便,把具体类依赖于具体类,也就是所谓的高层模块依赖于低层模块,但是这样是不利于扩展的,违反了设计原则,此时:
而现在根据依赖倒置原则,我们需要将高层模块和低层模块都依赖于接口(或者抽象类)来实现
这里发生了倒置,本来是高层模块依赖于低层模块,低层模块被高层模块依赖,现在是低层模块主动依赖于接口,所以发生了倒置,所以这个原则也称为依赖倒置原则
摘自于:https://blog.csdn.net/weixin_37505014/article/details/94869450
现在要完成一个Person类接收消息的需求;
方式1:
public class Inversion01 {
public static void main(String[] args) {
Person person = new Person();
person.receive(new Email());
}
}
// 完成Person接收消息的功能
class Email {
public String getInfo() {
return "电子邮件信息: HELLO WORLD";
}
}
class Person {
public void receive(Email email) {
System.out.println(email.getInfo());
}
}
输出结果:电子邮件信息: HELLO WORLD
这里面Email就是低层模块,而Person是高层模块,高层模块依赖于低层模块,不符合依赖倒置原则,Person类智能接受Email类而不可以接受其他类,要改的话就要每次改代码
该方式很简单的实现了需求,但是有一些问题,我们现在接收的是邮件,如果将来需求变更需要再加上一个可以接收短信的功能,那么我们就需要新增类。同时,Person类也要增加相应的接收方法。
改进:
解决思路,引入一个抽象接口Reveiver,表示接收者,这样Person类与接口发生依赖。因为Email, 短信都属于接收范围,它们各自实现Receiver接口就行了,这样我们就符合依赖倒转原则。
public class Inversion02 {
public static void main(String[] args) {
Person02 person02 = new Person02();
person02.receive(new Email02());
person02.receive(new Message());
}
}
//先定义一个接口
interface Receiver {
String getInfo();
}
class Email02 implements Receiver {
public String getInfo() {
return "电子邮件信息: HELLO WORLD";
}
}
//增加短信
class Message implements Receiver {
public String getInfo() {
return "短信信息: HELLO WORLD";
}
}
class Person02 {
// 这里我们是对接口的依赖,稳定性较好
public void receive(Receiver receiver) {
System.out.println(receiver.getInfo());
}
}
输出结果:电子邮件信息: HELLO WORLD,短信信息: HELLO WORLD
此时,高层模块(Person)和低层模块(Email和Message)都依赖于接口(Receive),符合依赖倒置原则
摘自:
https://blog.csdn.net/hfreeman2008/article/details/52289571?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control
这个例子里面有个图画错了,IReader和IRead的指向反了,其他没问题
在类中通过构造函数声明依赖对象,按照依赖注入的说法,这种方式叫做构造函数注入:
构造函数注入:
//小明类
public class XiaoMing implements IReader{
private IRead read;
//构造函数注入
public XiaoMing(IRead read){
this.read = read;
}
//阅读
public void read(){
read.read();
}
}
在类中通过Setter方法声明依赖关系,依照依赖注入的说法,这是Setter依赖注入:
//小明类
public class XiaoMing implements IReader{
private IRead read;
//Setter依赖注入
public setRead(IRead read){
this.read = read;
}
//阅读
public void read(){
read.read();
}
}
在接口的方法中声明依赖对象,该方法也叫做接口注入。
public interface IReader{
//阅读
public void read(IRead read){
read.read();
}
}
//IReader接口依赖于IRead 接口
依赖倒置原则的本质就是通过抽象(接口或抽象类)使各个类或模块的实现彼此独立,不互相影响,实现模块间的松耦合。我们在项目中使用这个原则要遵循下面的规则:
结合里氏替换原则使用
里氏替换原则:父类出现的地方子类就能出现。结合本章我们得出了一个通俗的规则:接口负责定义public属性和方法,并且声明与其他对象的依赖关系。抽象类负责公共构造部分的实现,实现类准确的实现业务逻辑,同时在适当的时候对父类进行细化。
依赖倒置原则是6个设计原则中最难以实现的原则,它是实现开闭原则的重要方法,在项目中,大家只要记住是”面向接口编程”就基本上是抓住了依赖倒置原则的核心了。