`

【编程思想】依赖倒置原则实例讲解

阅读更多

概述:

  所谓依赖倒置原则(Dependence Inversion Principle)就是要依赖于抽象,不要依赖于具体。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。

  意图:

  面向过程的开发,上层调用下层,上层依赖于下层,当下层剧烈变动时上层也要跟着变动,这就会导致模块的复用性降低而且大大提高了开发的成本。

  面向对象的开发很好的解决了这个问题,一般情况下抽象的变化概率很小,让用户程序依赖于抽象,实现的细节也依赖于抽象。即使实现细节不断变动,只要抽象不变,客户程序就不需要变化。这大大降低了客户程序与实现细节的耦合度。

  面向过程思想的结构图:

  

图一

  背景1:公司是福特和本田公司的金牌合作伙伴,现要求开发一套自动驾驶系统,只要汽车上安装该系统就可以实现无人驾驶,该系统可以在福特和本田车上使用,只要这两个品牌的汽车使用该系统就能实现自动驾驶。于是有人做出了分析如图一。

  对于图一分析:我们定义了一个AutoSystem类,一个FordCar类,一个HondaCar类。FordCar类和HondaCar类中各有三个方法:Run(启动Car)、Turn(转弯Car)、Stop(停止Car),当然了一个汽车肯定不止这些功能,这里只要能说明问题即可。AutoSystem类是一个自动驾驶系统,自动操纵这两辆车。

  代码实现:

  public class HondaCar {

		public void Run()  {
  			Console.WriteLine("本田开始启动了");
  		}
  		public void Turn()  {
  			Console.WriteLine("本田开始转弯了");
  		}
  		public void Stop()  {
  			Console.WriteLine("本田开始停车了");
  		}
  }
  public class FordCar
  {
  		public void Run() {
  			Console.WriteLine("福特开始启动了");
  		}
  		public void Turn() {
  			Console.WriteLine("福特开始转弯了");
  		}
  		public void Stop() {
  			Console.WriteLine("福特开始停车了");
  			}
  }
  public class AutoSystem
  {
  		public enum CarType{ Ford, Honda };
  		private HondaCar hcar = new HondaCar();
  		private FordCar fcar = new FordCar();
  		private CarType type;
  		public AutoSystem(CarType type) {
  			this.type = type;
  		}
  		private void RunCar() {
  			if (type == CarType.Ford) {
  				fcar.Run();
  			}
  			else {
  				hcar.Run();
  			}
  		}
  		private void TurnCar() {
 			if (type == CarType.Ford) {
  				fcar.Turn();
  			}
  			else {
  				hcar.Turn();
  			}
  		}
  			private void StopCar() {
 				if (type == CarType.Ford) {
  					fcar.Stop();
  				}
  				else {
  					hcar.Stop();
  				}
  			}
  }

 

  代码分析:上面的程序确实能够实现针对Ford和Honda车的无人驾驶,但是软件是在不断变化的,软件的需求也在不断的变化。

  背景2:公司的业务做大了,同时成为了通用、三菱、大众的金牌合作伙伴,于是公司要求该自动驾驶系统也能够安装在这3种公司生产的汽车上。于是我们不得不变动AutoSystem:

  public class AutoSystem

  {
  public enum CarType { Ford, Honda ,Bmw};
  HondaCar hcar = new HondaCar();
  FordCar fcar = new FordCar();
  BmwCar bcar = new BmwCar();
  private CarType type;
  public AutoSystem(CarType type)
  {
  this.type = type;
  }
  private void RunCar()
  {
  if (type == CarType.Ford)
  {
  fcar.Run();
  }
  else if (type == CarType.Honda)
  {
  hcar.Run();
  }
  else if (type == CarType.Bmw)
  {
  bcar.Run();
  }
  }
  private void TurnCar()
  {
  if (type == CarType.Ford)
  {
  fcar.Turn();
  }
  else if (type == CarType.Honda)
  {
  hcar.Turn();
  }
  else if (type == CarType.Bmw)
  {
  bcar.Turn();
  }
  }
  private void StopCar()
  {
  if (type == CarType.Ford)
  {
  fcar.Stop();
  }
  else if (type == CarType.Honda)
  {
  hcar.Stop();
  }
  else if (type == CarType.Bmw)
  {
  bcar.Stop();
  }
  }

 

  }分析:这会给系统增加新的相互依赖。随着时间的推移,越来越多的车种必须加入到AutoSystem中,这个“AutoSystem”模块将会被if/else语句弄得很乱,而且依赖于很多的低层模块,只要低层模块发生变动,AutoSystem就必须跟着变动,

  它最终将变得僵化、脆弱。

  导致上面所述问题的一个原因是,含有高层策略的模块,如AutoSystem模块,依赖于它所控制的低层的具体细节的模块(如HondaCar()和FordCar())。如果我们能够找到一种方法使AutoSystem模块独立于它所控制的具体细节,那么我们就可以自由地复用它了。我们就可以用这个模块来生成其它的程序,使得系统能够用在需要的汽车上。OOD给我们提供了一种机制来实现这种“依赖倒置”。

  结构图:

  

  图二

  看图 2中这个简单的类图。这儿有一个“AutoSystem”类,它包含一个“ICar”接口。这个“AutoSystem”类根本不依赖于“FordCar”和“HondaCar”。所以,依赖关系被“倒置”了:“AutoSystem”模块依赖于抽象,那些具体的汽车操作也依赖于相同的抽象。

  于是可以添加ICar

  


public interface ICar

  {
  void Run();
  void Turn();
  void Stop();
  }
  public class BmwCar:ICar
  {
  public void Run()
  {
  Console.WriteLine("宝马开始启动了");
  }
  public void Turn()
  {
  Console.WriteLine("宝马开始转弯了");
  }
  public void Stop()
  {
  Console.WriteLine("宝马开始停车了");
  }
  }
  public class FordCar:ICar
  {
  public void Run()
  {
  Console.WriteLine("福特开始启动了");
  }
  public void Turn()
  {
  Console.WriteLine("福特开始转弯了");
  }
  public void Stop()
  {
  Console.WriteLine("福特开始停车了");
  }
  }
  public class HondaCar:ICar
  {
  public void Run()
  {
  Console.WriteLine("本田开始启动了");
  }
  public void Turn()
  {
  Console.WriteLine("本田开始转弯了");
  }
  public void Stop()
  {
  Console.WriteLine("本田开始停车了");
  }
  }
  public class AutoSystem
  {
  private ICar icar;
  public AutoSystem(ICar icar)
  {
  this.icar = icar;
  }
  private void RunCar()
  {
  icar.Run();
  }
  private void TurnCar()
  {
  icar.Turn();
  }
  private void StopCar()
  {
  icar.Stop();
  }
  }

 

现在AutoSystem系统依赖于ICar 这个抽象,而与具体的实现细节HondaCar、FordCar、BmwCar无关,所以实现细节的变化不会影响AutoSystem。对于实现细节只要实现ICar 即可,即实现细节依赖于ICar 抽象。

  

 

综上:

  一个应用中的重要策略决定及业务模型正是在这些高层的模块中。也正是这些模型包含着应用的特性。但是,当这些模块依赖于低层模块时,低层模块的修改将会直接影响到它们,迫使它们也去改变。这种境况是荒谬的。应该是处于高

  层的模块去迫使那些低层的模块发生改变。应该是处于高层的模块优先于低层的模块。无论如何高层的模块也不应依赖于低层的模块。而且,我们想能够复用的是高层的模块。通过子程序库的形式,我们已经可以很好地复用低层的模块了。当高层的模块依赖于低层的模块时,这些高层模块就很难在不同的环境中复用。但是,当那些高层模块独立于低层模块时,它们就能很简单地被复用了。这正是位于框架设计的最核心之处的原则。

 

  总结:依赖倒置原则

  A.高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。

  B.抽象不应该依赖于具体,具体应该依赖于抽象。

 

分享到:
评论

相关推荐

    java基础编程思想

    面向对象设计原则如单一职责、开闭原则、里氏替换原则、依赖倒置原则等也会有所涉及。 2. **基本语法与数据类型**:Java有八种基本数据类型,包括整型、浮点型、字符型和布尔型。书中会详细解释这些类型的特点以及...

    delphi面向对象编程思想PDF电子书

    在实践部分,作者刘艺可能会通过一系列的实例,展示如何在Delphi中实现面向对象的设计原则,如单一职责原则、开闭原则、里氏替换原则、依赖倒置原则等,帮助读者掌握良好的编程习惯和设计模式。同时,书中可能还涵盖...

    零分下载:C++编程思想清晰电子版

    面向对象编程不仅仅是关于语法和技术,它还涉及到设计原则和实践,如 SOLID 原则(单一职责、开闭、里氏替换、接口隔离和依赖倒置),这些原则可以帮助写出更易于理解和维护的代码。 总的来说,《C++编程思想》这...

    C++编程思想(中文版).rar

    面向对象设计原则,如单一职责原则、开闭原则、里氏替换原则、依赖倒置原则等也会有深入讨论。 3. **模板**:C++的模板机制允许开发者创建泛型代码,提高代码复用性。书中会讲解模板的用法,包括函数模板、类模板、...

    实例讲解Java设计模式编程中的OCP开闭原则

    它与其他面向对象设计原则(如单一职责原则、里氏替换原则、依赖倒置原则和接口隔离原则)相互关联,共同促进代码质量的提升。例如,单一职责原则确保每个类或模块只负责一个功能,而里氏替换原则保证了子类可以替换...

    C++编程思想(共十八章,适合一定基础者)

    8. **设计原则**:本书可能还会讨论一些软件设计的原则,如 SOLID 原则(单一职责原则、开放封闭原则、里氏替换原则、接口隔离原则、依赖倒置原则),帮助读者编写出高质量的C++代码。 每个PDF文件可能对应一章或一...

    CBF4LIFE的《设计模式讲解JAVA》

    3. 依赖倒置原则(Dependence Inversion Principle):高层模块不应该依赖低层模块,两者都应该依赖其抽象。 4. 接口隔离原则(Interface Segregation Principle):不应该强迫客户依赖于它们不用的方法。 5. 迪米特...

    斯坦福—编程方法讲义

    7. **软件设计原则**:讲解SOLID原则,即单一职责原则、开闭原则、里氏替换原则、接口隔离原则和依赖倒置原则,这些原则指导着高质量软件的构建。 8. **项目管理与团队协作**:简述敏捷开发、Scrum框架,以及如何...

    《Thinking in C++》pdf电子版

    此外,《Thinking in C++》还会介绍一些设计原则和模式,如 SOLID 原则(单一职责原则、开放封闭原则、里氏替换原则、接口隔离原则、依赖倒置原则),以及工厂模式、观察者模式、装饰器模式等经典设计模式,这些都是...

    Head First 设计模式(中文版)

    此外,书中还强调了SOLID原则,这是面向对象设计的五个基本原则,包括单一职责原则、开放封闭原则、里氏替换原则、接口隔离原则和依赖倒置原则。这些原则指导我们编写出高质量、易于维护的代码。 《Head First 设计...

    java设计模式

    - 依赖倒置原则:高层模块不应该依赖低层模块,两者都应该依赖其抽象。 - 接口隔离原则:不应该强迫客户依赖于它们不用的方法。 - 迪米特法则(最少知识原则):只与你直接朋友通信。 - 开闭原则:软件实体应对扩展...

    敏捷软件开发+原则、模式与实践.pdf

    例如,他强调面向对象设计的重要性,提倡使用设计原则,如单一职责、开闭原则、依赖倒置原则等,以提高软件设计的质量。 此外,书中还包含了大量可复用的C++和Java源代码示例。这些代码示例不仅展示了如何实现特定...

    961-复旦大学计算机科学技术学院 软件工程(第二版)

    接着,我们需要掌握不同的软件设计模式和原则,如工厂模式、单例模式等设计模式在实际开发中的应用,以及 SOLID 原则(单一职责原则、开放封闭原则、里氏替换原则、接口隔离原则和依赖倒置原则)如何指导我们编写可...

    Design-Principles

    "Design-Principles"这个主题涵盖了多个重要的设计原则,包括单一职责原则(SRP)、开闭原则(OCP)、里氏替换原则(LSP)、接口隔离原则(ISP)、依赖倒置原则(DIP)以及合成复用原则(CRP)。 1. **单一职责原则...

    敏捷软件开发:原则、模式与实践.pdf

    第11章 依赖倒置原则(DIP) 第12章 接口隔离原则(ISP) 第三部分 薪水支付案例研究 第13章 COMMAND模式和ACTIVE OBJECT模式 第14章 TEMPLATE METHOD模式和STRATEGY模式:继承与委托 第15章 FACADE模式和MEDIATOR...

    道法自然 面向对象实践指南8-8

    开闭原则(OCP)使软件模块对扩展开放,对修改关闭,里氏替换原则(LSP)保证子类型必须能够替换它们的基类型,接口隔离原则(ISP)避免强迫客户依赖他们不需要的方法,依赖倒置原则(DIP)让程序依赖于抽象而不是...

    OOAD系列PPT

    第二章“设计原则”探讨了软件设计中的重要原则,如单一职责原则(SRP)、开闭原则(OCP)、里氏替换原则(LSP)、依赖倒置原则(DIP)、接口隔离原则(ISP)和迪米特法则(LoD)。这些原则是优秀设计的基础,能指导...

    03第三章面向对象的设计与实现.ppt共60页.pdf.z

    - SOLID原则:SOLID是五个面向对象设计原则的缩写,包括单一职责原则、开闭原则、里氏替换原则、接口隔离原则和依赖倒置原则,它们指导我们编写更健壮、可维护的代码。 4. 面向对象实现: - 在Java和C#等面向对象...

Global site tag (gtag.js) - Google Analytics