定义

  1. 上层模块不应该依赖底层模块,它们都应该依赖于抽象。
  2. 抽象不应该依赖于细节,细节应该依赖于抽象。

    High level modules should not depend upon low level modules. Both should depend upon abstractions.
    Abstractions should not depend upon details. Details should depend upon abstractions.

在依赖倒置原则中的倒置指的是和一般OO设计的思考方式完全相反。
举个例子,现在你需要实现一个比萨店,你第一件想到的事情是什么?我想到的是一个比萨店,里面有很多具体的比萨,如:芝士比萨、素食比萨、海鲜比萨……
比萨店是上层模块,比萨是下层模块,如果把比萨店和它依赖的对象画成一张图,看起来是这样:
image.png
没错!先从顶端开始,然后往下到具体类,但是,正如你看到的你不想让比萨店理会这些具体类,要不然比萨店将全都依赖这些具体类。现在“倒置”你的想法……别从上层模块比萨店开始思考,而是从下层模块比萨开始,然后想想看能抽象化些什么。你可能会想到,芝士比萨、素食比萨、海鲜比萨都是比萨,所以它们应该共享一个Pizza接口。对了,你想要抽象化一个Pizza。好,现在回头重新思考如何设计比萨店。
image.png
图一的依赖箭头都是从上往下的,图二的箭头出现了从下往上,依赖关系确实“倒置”了。

案例:打印机

需求:打印机打印文档时,可以打印html和pdf格式。现在有如下代码:

  1. public class Printer {
  2. Document doc;
  3. HtmlFormatter htmlFormatter;
  4. PdfFormatter pdfFormatter;
  5. // 打印pdf格式
  6. public void printPdf() {
  7. String txt = pdfFormatter.format(doc);
  8. print(txt);
  9. }
  10. // 打印html格式
  11. public void printHtml() {
  12. String txt = htmlFormatter.format(doc);
  13. print(txt);
  14. }
  15. private void print(String txt) {
  16. // 打印
  17. }
  18. }

我们的打印机Printer依赖了打印html和pdf的HtmlFormatter和PdfFormatter,这样不太合理。

根据依赖倒置原则,打印成html,打印成pdf可以抽象成一个Formatter,然后让Printer依赖于Formatter而不依赖于具体的HtmlFormatter和PdfFormatter。

优化之后的代码如下:

  1. public class Printer {
  2. Document doc;
  3. Formatter formatter;
  4. public void print() {
  5. String txt = formatter.format(doc);
  6. print(txt);
  7. }
  8. private void print(String txt) {
  9. // 打印
  10. }
  11. }

参考链接

https://www.jianshu.com/p/c3ce6762257c