今天的博客主题
设计原则和模式 --》设计原则之依赖倒置原则
依赖倒置原则 DIP (Dependence Inversion Principle )
是说在设计代码结构的时候,高层模块不应该依赖底层模块,二者都应该依赖于抽象。
抽象不依赖细节,细节依赖于抽象。
这样可以减少类与类之间的耦合性,能提高系统的稳定性,提高代码可读性与可维护性,降低修改程序造成的风险。
代码示例:
比如销售人员销售手机,新建一个销售类
public class Sale {
public void saleApplePhone(){
System.out.println("销售人员销售苹果手机");
}
public void saleHuaweiPhone(){
System.out.println("销售人员销售华为手机");
}
}
调用下:
public class DemoDIP {
public static void main(String[] args) {
Sale sale = new Sale();
sale.saleApplePhone();
sale.saleHuaweiPhone();
}
}
销售人员现在销售这两种手机,现在店里新进 小米 手机了,这是必然的,不是专卖店,就买的手机品牌多一些。
这时候,属于业务扩展了。代码得改,从底层到高层(调用层为高层)。
在 Sale 类增加 saleXiaoMiPhone(); 方法,在高层代码块也要增加调用。
这样一来,系统发布之后,实际上系统就不那么稳定了。因为在修改代码的时候,会带来意想不到的一些风险。
在之前的开发模式当中 我觉得很多是这样做的。
重构代码===》
抽出一个销售接口:
public interface ISale {
void sale();
}
华为苹果手机都来实现这个接口:
public class SaleHuaWeiPhone implements ISale {
public void sale() {
System.out.println("销售人员销售华为手机");
}
}
public class SaleApplePhone implements ISale {
public void sale() {
System.out.println("销售人员销售苹果手机");
}
}
修改 销售类:
public class Sale {
public void salePhone(ISale sale){
sale.sale();
}
}
修改 调用层:
public class DemoDIP {
public static void main(String[] args) {
Sale sale = new Sale();
sale.salePhone(new SaleHuaWeiPhone());
sale.salePhone(new SaleApplePhone());
}
}
重构成这样的代码之后,以后无论在新增销售什么牌子的手机,对于新扩展的业务,只需要新建一个类,通过传参的方式告诉 销售类
不修改底层代码,不影响原有业务。
实际上这是一种大家比较熟悉的方式,依赖注入。
除了这种方式,还有构造器注入和 setter 两种方式注入。
构造器注入:
public class Sale {
private ISale sale;
public Sale(ISale sale){
this.sale = sale;
}
public void salePhone(){
sale.sale();
}
}
调用层:
public class DemoDIP {
public static void main(String[] args) {
Sale sale = new Sale(new SaleHuaWeiPhone());
sale.salePhone();
}
}
如果通过这种方式注入,可以发现每次都会创建一个新的实例对象。
如果这个 Sale 是全局单例,那只能用 setter 方式注入了。
Setter 注入:
public class Sale {
private ISale sale;
public void setCource(ISale sale){
this.sale = sale;
}
public void salePhone(){
sale.sale();
}
}
调用层:
public class DemoDIP {
public static void main(String[] args) {
Sale sale = new Sale();
sale.setCource(new SaleHuaWeiPhone());
sale.salePhone();
sale.setCource(new SaleApplePhone());
sale.salePhone();
}
}
最终类图
以抽象为基准比以细节为基准搭建起来的架构要稳定。
在开发过程中要面向接口去编程,遵守 先顶层 在细节 来设计架构。