本文将作为我正在撰写的书的一部分思路,换言之,yqj2065正式抛弃依赖倒置原则。
依赖倒置原理、DIP: 1. High level modules should not depend upon low level modules,both should depend upon abstractions. 2. Abstractions should not depend upon details,details should depend upon abstractions.
很多人介绍过DIP,yqj2065在本博客中就发布过The Dependency Inversion Principle(翻译)(2005-01-28 00:22)。这是一个难解的原则,因为我认为Robert C. Martin自己都不知道他想说什么。
按照我不愿意费脑的习惯,yqj2065将DIP和面向接口编程等同看待。或者用我自己的话:
★抽象依赖原则:为了应对需求变化,代码中要尽可能地依赖抽象类型,而非具体类。
但是,Robert C. Martin显然更加野心勃勃,他希望把两个议题用一个原则说出来,但是说得云山雾绕。
这两个议题是:
- 针对抽象(类型)编程
- 框架设计时,必须针对抽象(类型)编程。
1解读
在讨论依赖时,
既然子类型显然地依赖父类型,所以我们不需要再考虑它。于是,依赖倒置原则中的“抽象不应该依赖细节。细节应该依赖抽象”多余。
那么,依赖倒置原则中第一条,Robert C. Martin为什么没有采用我们容易理解的
Client-Server,而是使用
High -lowlevel modules呢?这就是他“野心勃勃”的证明。
他的高层模块——“包含一个应用的重要策略决定和商业模式”,其实按照控制反转中的说法,即控制模块。在我上课的例子中就是TestSortor 。
这个TestSortor ,有两个用法。
(1)在底层包util中有BubbleSort等,而学生编写TestSortor 包含main属于上层模块。上层模块必然依赖下层模块,如同你的app依赖JDK一样。
(2)如果TestSortor 是老师编写的下层模块,要求你编写属于上层模块等BubbleSort,并且要求你使用TestSortor 进行测试,这个TestSortor 和接口IntSort 构成框架。
现在,你应该清楚,Robert C. Martin使用
High -lowlevel modules,指的就是TestSortor -BubbleSort的关系。而这种关系,Robert C. Martin又仅仅强调TestSortor 作为框架的情形。
必然地,你按照属于上层模块的TestSortor 即情形(1)考虑依赖倒置,你不知道哪里倒置了。
在框架设计时,TestSortor 只能依赖接口IntSort ,IntSort 的实现类,还不知道别人什么时候编写呢,你如何依赖?
按照上述分析,我们将依赖倒置原则如下解读:
1.作为一般性原则,为了应对需求变化,代码中要尽可能地
/应该依赖抽象类型。
2.框架设计时,控制模块
必须依赖抽象类型;
3.控制模块可以作为上层模块,也可以作为下层模块,两种的差别体现了控制反转。
2.抛弃DIP
既然我们清楚地理解了DIP的含义,就知道依赖倒置原则多么混乱。
1该说清楚的地方,不分青红皂白;他没有告诉我们 必须和应该。
2.不该说到的第2条,画蛇添足;
3.针对抽象(类型)编程和原则的名字,同床异梦。
好吧,这就是我抛弃依赖倒置原则的原因。
Robert C. Martin最令我不爽的话: