基本介绍:
依赖原则是指:
高层模块不应该依赖底层模块,二者都应该依赖其抽象
抽象不应该依赖细节,细节应该依赖抽象
依赖倒转的中心思想是面向接口编程
依赖倒转原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比细节为基础的架构要稳定的多。在java中,抽象指的是接口或抽象类,细节就是具体的实现类。
使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成
应用实例:
Person接受消息的功能
方式一:
package cn.rabcheng.dependenceinversion;
/**
* @auther cheng
* @create 2020-08-13 22:41
* 依赖倒转原则
*/
public class dependenceinversion1 {
public static void main(String[] args) {
Person person = new Person();
person.receive(new Email());
person.receive2(new Weixin());
}
}
class Email{
public String getInfo(){
return "电子邮件信息:hello world";
}
}
class Weixin{
public String getInfo(){
return "微信消息:hello ok";
}
}
//完成Person接受消息的功能
class Person{
public void receive(Email email){
System.out.println(email.getInfo());
}
public void receive2(Weixin weixin){
System.out.println(weixin.getInfo());
}
}
电子邮件信息:hello world
微信消息:hello ok
方式一的分析:
简单,比较容易想到、实现
如果我们获取的对象是微信、短信等等,则新增类,同时Person也要增加相应的接受方法
解决思路:引入一个抽象的接口IReceiver,表示接收者,这样Person类与IReceiver发生依赖
因为Email,Weixin等等属于接收的范围,他们各自实现IReceiver接口就行,这样我们就符合依赖倒转的原则
方式二:
1 package cn.rabcheng.dependenceinversion; 2 3 /** 4 * @auther cheng 5 * @create 2020-08-13 22:57 6 * 依赖倒转原则 7 */ 8 public class dependenceinversion2 { 9 public static void main(String[] args) { 10 11 //客户端无需改变 12 Person2 person2 = new Person2(); 13 person2.receive(new Email2()); 14 person2.receive(new Weixin2()); 15 16 17 } 18 } 19 20 //定义接口 21 interface IReceiver{ 22 String getInfo(); 23 } 24 25 26 class Email2 implements IReceiver{ 27 @Override 28 public String getInfo() { 29 return "电子邮件信息:hello world"; 30 } 31 } 32 33 //增加微信 34 class Weixin2 implements IReceiver{ 35 @Override 36 public String getInfo() { 37 return "微信消息:hello ok"; 38 } 39 } 40 41 class Person2{ 42 //person2依赖接口 43 public void receive(IReceiver iReceiver){ 44 System.out.println(iReceiver.getInfo()); 45 } 46 } 47 电子邮件信息:hello world 48 微信消息:hello ok
这样只需要增加Weixin类,不用增加Person类里面的方法,让Person类和IReceiver发生依赖关系。
依赖关系传递的三种方式和应用案例:
接口传递
构造方法传递
setter方法传递
1 package cn.rabcheng.dependenceinversion; 2 3 /** 4 * @auther cheng 5 * @create 2020-08-13 23:10 6 * 依赖传递 7 */ 8 public class DependencyPass { 9 public static void main(String[] args) { 10 11 // 方式一:通过接口传递 12 // Open open = new Open(); 13 // open.open(new XiaoMi()); 14 15 // 方式二:通过构造方法传递 16 // Open open = new Open(new XiaoMi()); 17 // open.open(); 18 19 // 方式三:通过setter方法传递 20 Open open = new Open(); 21 XiaoMi xiaoMi = new XiaoMi(); 22 open.setter(xiaoMi); 23 open.open(); 24 } 25 } 26 27 //方式一:通过接口传递依赖 28 //开电视的接口 29 //interface IOpen{ 30 // void open(ITV itv); 31 //} 32 // 33 ////电视机接口 34 //interface ITV{ 35 // void play(); 36 //} 37 // 38 //class XiaoMi implements ITV{ 39 // @Override 40 // public void play() { 41 // System.out.println("小米电视,打开"); 42 // } 43 //} 44 // 45 //class Open implements IOpen{ 46 // @Override 47 // public void open(ITV itv) { 48 // itv.play(); 49 // } 50 //} 51 52 //方式二:通过构造方法传递依赖 53 //interface IOpen{ 54 // void open(); 55 //} 56 // 57 //interface ITV{ 58 // void play(); 59 //} 60 // 61 //class XiaoMi implements ITV{ 62 // @Override 63 // public void play() { 64 // System.out.println("小米电视,打开"); 65 // } 66 //} 67 // 68 //class Open implements IOpen{ 69 // private ITV itv; 70 // public Open(ITV itv) { 71 // this.itv = itv; 72 // } 73 // 74 // @Override 75 // public void open() { 76 // this.itv.play(); 77 // } 78 //} 79 80 81 //方式三:通过setter方法传递 82 interface IOpen{ 83 void open(); 84 } 85 86 interface ITV{ 87 void play(); 88 } 89 90 class Open implements IOpen{ 91 private ITV itv; 92 93 public void setter(ITV itv){ 94 this.itv = itv; 95 } 96 @Override 97 public void open() { 98 this.itv.play(); 99 } 100 } 101 102 class XiaoMi implements ITV{ 103 @Override 104 public void play() { 105 System.out.println("小米电视,打开"); 106 } 107 }
依赖倒转原则的注意事项和细节:
底层模块尽量都要有抽象类或接口,或者两者都有,程序稳定性更好
变量的声明类型尽量是抽象类或接口,这样我们的变量引用和实际对象间,就存在一个缓冲层,利于程序扩展和优化
继承时应遵循里氏替换原则