标准定义
高层模块不应该依赖底层模块,两者都应该依赖抽象。抽象不应该依赖细节,细节应该依赖于抽象
生活案例
我们家里有许多插座,有的插座的是两个孔的,有的插座是三个孔的,我们买的家电都能够直接插入插座,通电使用,原因很简单,他们是适配使用的。
在不同的国家,插座的样子是不同的,有的孔是圆的,有些孔是方的,有两个孔的,也有三个孔的,在中国买的家电是不能直接插入美国的插座中,因为插头🔌和插座的类型不同,不能适配使用。
不同国家的插座标准这个就是接口,接口就是大家坐下来一起商定的一种标准。如果插座和插头不遵守一个标准,我们会面临什么问题?假设我们有一个家电厂A,他有一个特别牛逼的产品,是一个风扇,风扇吹出来的风是冷的,但是他的插头是四个孔的,有一个孔是地线,一个是火线,一个零线,还有一个是冷线。前几个大家都知道是什么,最后一个冷线在这里解释一下,就是通冷气的线。这样的一款产品推出了市场,大家觉得特别牛逼,用一个风扇就能得到空调的效果,纷纷购买。买回去之后,就懵逼了,这插头是四个孔的,但是家里的插座有两个孔的,也有三个孔的,唯独没有四个孔的,于是纷纷退货,A厂也因为这个牛逼的产品而倒闭了。
A厂为什么会倒闭?就是因为它不遵循标准,不使用国标的三孔或者二孔的插座。当然,它可以为了这个牛逼的产品去设计一个插座,但是这样的设计和生产的成本会变得很高,也很难推广。既然有了一个牛逼的产品是用四孔插座的,我相信他将来也能设计出使用五孔插头的家电,那时候,也为了这个家电,设计推广一个五孔插座也会提上议程,这显然是不合理的。我们不是设计出一个家电,然后还得设计出相应的插座配套使用,不按标准来,成本会变得越来越高。
怎么办?就是根据依赖倒转原则,插座不能因为插头的改变而改变,他们两个应该坐下来,指定一个统一的标准,以后的插头和插座的样式都得按这个标准执行,那么,就不会出现插座和插头不停更改,同时设计的情况了。
程序代码
程序的业务按03. 单一功能原则来定,我们的打印机,可以添加黑色的墨水,我们严格不按照依赖倒转原则来写代码,那么我们可以写出这样的代码。
public class BlackInk {
}
public class CanonPrinter{
public void addInk(BlackInk blackInk) {
System.out.println("使用"+blackInk+"的墨水打印");
}
}
public class Main {
public void main() {
BlackInk ink = new BlackInk();
CanonPrinter printer = new CanonPrinter();
printer.addInk(ink);
}
}
当只有一种墨水的时候,这样的写法并没有什么问题,但是当我们添加红色的墨水,这时候,我们需要在CanonPrinter添加一个addInk(RedInk redInk)的方法。
public class CanonPrinter{
public void addInk(RedInk redInk) {
System.out.println("使用"+redInk+"的墨水打印");
}
}
当我们要添加蓝色、绿色、黄色、紫色、青色... ...的墨水的时候,就意味着,addInk的方法得不停地写,最后造成了CanonPrinter的一整个类,都充满了addInk的方法,而且他们的入参都是不同的。
如果我们使用依赖倒转原则,这个问题就能得到很好地解决了,我们会写这样的代码:
public class BlackInk implements IInk{
}
public class CanonPrinter implements IPrinter{
public void addInk(IInk ink) {
System.out.println("使用"+ink+"的墨水打印");
}
}
public class Main {
public void main() {
IInk black = new BlackInk();
IPrinter printer = new CanonPrinter();
printer.addInk(black);
}
}
这样,对于addInk这个方法,我们只需要写一遍就可以了。如果有红色的墨水,那么我们只需要实例化红色的墨水,并把它传入addInk中,剩下的就交个Java的多态帮我们完成。
public class RedInk implements IInk{
}
public class Main {
public void main() {
IInk black = new BlackInk();
IInk red = new RedInk();
IPrinter printer = new CanonPrinter();
printer.addInk(black);
printer.addInk(red);
}
}
今晚的例子真难想,自己还是不够掌握,一直都是使用面向接口编程,倒没想过为什么要面向接口编程。
终于想到了。
网友评论