5.3 依赖倒转原则

“小菜走桃花运了哦,”大鸟有些羡慕道,“那铃声看来有些效果,不过还是换掉吧,俗!”

“嘿嘿,你说也怪,修电脑,这在以前根本不可能的事,怎么就可以通过电话就教会了,而且是真的修到可以用了呢。”

“你有没有想过这里的最大原因?”大鸟开始上课了。

“蓝屏通常是内存本身有问题或内存与主板不兼容,主板不容易换,但内存更换起来很容易。”

“如果是别的部件坏了,比如硬盘,显卡,光驱等,是否也只需要更换就可以了?”

“是呀,确实很方便,只需要懂一点点计算机知识,就可以试着修电脑了。”

“想想这和我们编程有什么联系?”

“你的意思又是——面向对象?”

“嗯,说说看,面向对象的四个好处?”

“这个我记得最牢了,就是活字印刷那个例子呗。是可维护、可扩展、可复用和灵活性好。哦,我知道了,可以把PC电脑理解成是大的软件系统,任何部件如CPU、内存、硬盘、显卡等都可以理解为程序中封装的类或程序集,由于PC易插拔的方式,那么不管哪一个出问题,都可以在不影响别的部件的前提下进行修改或替换。”

“PC电脑里叫易插拔,面向对象里把这种关系叫什么?”

“应该是叫强内聚、松耦合吧。”

“对的,非常好,我们电脑里的CPU全世界也就是那么几家生产的,大家都在用,但却不知道Intel、AMD等公司是如何做出这个精密的小东西的。去年国内不是还出现了汉芯造假的新闻吗!这就说明CPU的强内聚的确是强。但它又独自成为了产品,在千千万万的电脑主板上插上就可以使用,这是什么原因?”大鸟又问。

“因为CPU的对外都是针脚式或触点式等标准的接口。啊,我明白了,这就是接口的最大好处。CPU只需要把接口定义好,内部再复杂我也不让外界知道,而主板只需要预留与CPU针脚的插槽就可以了。”

“很好,你已经在无意的谈话间提到了面向对象的几大设计原则,比如我们之前讲过的单一职责原则,就刚才修电脑的事,显然内存坏了,不应该成为更换CPU的理由,它们各自的职责是明确的。再比如开放-封闭原则,内存不够只要插槽足够就可以添加,硬盘不够可以用移动硬盘等,PC的接口是有限的,所以扩展有限,软件系统设计得好,却可以无限地扩展。这两个原则我们之前都已经提过了。这里需要重点讲讲一个新的原则,叫依赖倒转原则,也有翻译成依赖倒置原则的。”大鸟接着讲道,“依赖倒转原则,原话解释是抽象不应该依赖细节,细节应该依赖于抽象,这话绕口,说白了,就是要针对接口编程,不要对实现编程,无论主板、CPU、内存、硬盘都是在针对接口设计的,如果针对实现来设计,内存就要对应到具体的某个品牌的主板,那就会出现换内存需要把主板也换了的尴尬。你想在小MM面前表现也就不那么容易了。所以说,PC电脑硬件的发展,和面向对象思想发展是完全类似的。这也说明世间万物都是遵循某种类似的规律,谁先把握了这些规律,谁就最早成为了强者。”

依赖倒转原则

A.高层模块不应该依赖低层模块。两个都应该依赖抽象。

B.抽象不应该依赖细节。细节应该依赖抽象。[ASD]

“为什么要叫倒转呢?”小菜问道。

“这里面是需要好好解释一下,面向过程的开发时,为了使得常用代码可以复用,一般都会把这些常用代码写成许许多多函数的程序库,这样我们在做新项目时,去调用这些低层的函数就可以了。比如我们做的项目大多要访问数据库,所以我们就把访问数据库的代码写成了函数,每次做新项目时就去调用这些函数。这也就叫做高层模块依赖低层模块。”

“嗯,是这样的,我以前都是这么做的。这有什么问题?”

“问题也就出在这里,我们要做新项目时,发现业务逻辑的高层模块都是一样的,但客户却希望使用不同的数据库或存储信息方式,这时就出现麻烦了。我们希望能再次利用这些高层模块,但高层模块都是与低层的访问数据库绑定在一起的,没办法复用这些高层模块,这就非常糟糕了。就像刚才说的,PC里如果CPU、内存、硬盘都需要依赖具体的主板,主板一坏,所有的部件就都没用了,这显然不合理。反过来,如果内存坏了,也不应该造成其他部件不能用才对。而如果不管高层模块还是低层模块,它们都依赖于抽象,具体一点就是接口或抽象类,只要接口是稳定的,那么任何一个的更改都不用担心其他受到影响,这就使得无论高层模块还是低层模块都可以很容易地被复用。这才是最好的办法。”

“为什么依赖了抽象的接口或抽象类,就不怕更改呢?”小菜依然疑惑,“不好意思,我有些钻牛角尖了。”

“没有,没有,在这里弄不懂是很正常的,原因是我少讲了一个设计原则,使得你产生了困惑,这个原则就是里氏代换原则。”