面向对象的设计原则五 - 依赖倒转原则 - 森林狼 - JavaEye技术网站

来源:百度文库 编辑:神马文学网 时间:2024/07/05 21:32:32

动机

在一个应用程序中,我们有一些实现了基础的、主要的操作的底层类和一些封装了复杂逻辑的上层类。实现这种结构的很自然地方式就是,先编写底层类,完成后再编写复杂的上层类。因为上层类是由其他东西定义的,所以这看起来是一种很合理的方式。但是这不是一个灵活的设计,如果我们需要替换一个底层类时会发生什么?

 

让我们以经典的拷贝程序为例,它从键盘读取一些字符,然后把他们输出到打印设备上。包含该逻辑的上层类是Copy类,底层类是KeyboardReader和PrinterWriter。

 

在一个不好的设计中,上层类直接使用底层的类,在这种情况下,如果我们想要把输出定向到新的FileWriter类,就必须修改Copy类的代码(假设它是一个具有很多逻辑的复杂类并且很难测试)。

 

为了避免这种问题,我们可以在上层类和底层类之间引入一个抽象层。因为上层模块包含复杂的逻辑,所以它们不应该依赖于底层模块,新的抽象层也不应该基于底层模块而创建。底层模块应该基于抽象层而创建。

 

基于这个原则,设计类结构的方式应该是从上层模块到底层模块。

上层类--->抽象层--->底层类

 

依赖倒转原则

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

实例

下面是一个违反了依赖倒转原则的例子。我们有一个上层类Manager和底层类Worker。我们需要在程序中添加一个新模块,因为有新的特殊的工作者被雇用。为此,我们创建一个新的类SuperWorker。

 

我们假设Manager是一个包含非常复杂的逻辑的类,现在为了引入新的SuperWorker,我们需要修改它。让我们看一下这有哪些缺点:

  • 我们需要修改Manager类(记住,它是一个非常复杂的类,这需要一些时间和努力)。
  • Manager类的一些现有功能可能会受到影响。
  • 需要重做单元测试。

所有的这些问题需要大量的时间去解决。但是如果程序的设计符合依赖倒转原则将会非常简单。意思是我们设计Manager类和一个IWorker接口以及一些实现了该接口的Worker类。当需要添加SuperWorker类时我们只需要让它实现IWorker接口。

 

Java代码
  1. //Dependency Inversion Principle - Bad example   
  2. class Worker {   
  3.     public void work() {   
  4.         // ....working   
  5.     }   
  6. }   
  7.   
  8. class Manager {   
  9.     Worker m_worker;   
  10.   
  11.     public void setWorker(Worker w) {   
  12.         m_worker=w;   
  13.     }   
  14.   
  15.     public void manage() {   
  16.         m_worker.work();   
  17.     }   
  18. }   
  19.   
  20. class SuperWorker {   
  21.     public void work() {   
  22.         //.... working much more   
  23.     }   
  24. }  

 

 

下面是支持依赖倒转原则的代码。在这个新的设计中,我们增加了一个新的抽象层IWork接口。现在,上面的问题得到了解决:

  • 不需要修改Manager类。
  • 使对Manager类现有功能的影响最小化。
  • 不需要对Manager类重新进行单元测试。
Java代码
  1. //Dependency Inversion Principle - Good example   
  2. interface IWorker {   
  3.     public void work();   
  4. }   
  5.   
  6. class Worker implements IWorker{   
  7.     public void work() {   
  8.         // ....working   
  9.     }   
  10. }   
  11.   
  12. class SuperWorker  implements IWorker{   
  13.     public void work() {   
  14.         //.... working much more   
  15.     }   
  16. }   
  17.   
  18. class Manager {   
  19.     IWorker m_worker;   
  20.   
  21.     public void setWorker(IWorker w) {   
  22.         m_worker=w;   
  23.     }   
  24.     public void manage() {   
  25.         m_worker.work();   
  26.     }   
  27. }  

 

 

总结

应用该原则意味着上层类不直接使用底层类,他们使用接口作为抽象层。这种情况下上层类中创建底层类的对象的代码不能直接使用new操作符。可以使用一些创建型设计模式,例如工厂方法,抽象工厂和原型模式。

模版设计模式是应用依赖倒转原则的一个例子。

当然,使用该模式需要额外的努力和更复杂的代码,不过可以带来更灵活的设计。不应该随意使用该原则,如果我们有一个类的功能很有可能在将来不会改变,那么我们就不需要使用该原则。

面向对象的设计原则五 - 依赖倒转原则 - 森林狼 - JavaEye技术网站 面向对象的设计原则一 开放-关闭原则 - 森林狼 - JavaEye技术网站 面向对象的设计原则三 - 接口隔离原则 - 森林狼 - JavaEye技术网站 面向对象设计原则七 - 组合优先于继承 - 森林狼 - JavaEye技术网站 面向对象设计原则六 - 针对接口编程,而不是针对实现编程 - 森林狼 - JavaEye技... 面向对象设计原则 [JAVA技术]61条面向对象设计的经验原则 [JAVA技术]61条面向对象设计的经验原则 面向对象的设计原则-类设计原则 61条面向对象设计的经验原则61条面向对象设计的经验原则 面向对象的设计原则-类设计原则 ——希赛网软件工程频道面向对象 61条面向对象设计的经验原则 初学必读:61条面向对象设计的经验原则 61条面向对象设计的经验原则 61条面向对象设计的经验原则 61条Java面向对象设计的经验原则 面向对象编程五大原则 理解: 面向对象的设计原则与设计模式 - 积累与坚持 - C++博客 C#面向对象设计模式纵横谈:面向对象设计模式与原则 面向对象设计原则之单一职责 - 51CTO.COM 61条面向对象设计的经验原则 - opspring的专栏 61条面向对象的设计原则 - C Programmer's Cookbook - C... 61条面向对象的设计原则 - C Programmer‘s Cookbook - C... 61条面向对象的设计原则 - C Programmer's Cookbook - C...