动机
在一个应用程序中,我们有一些实现了基础的、主要的操作的底层类和一些封装了复杂逻辑的上层类。实现这种结构的很自然地方式就是,先编写底层类,完成后再编写复杂的上层类。因为上层类是由其他东西定义的,所以这看起来是一种很合理的方式。但是这不是一个灵活的设计,如果我们需要替换一个底层类时会发生什么?
让我们以经典的拷贝程序为例,它从键盘读取一些字符,然后把他们输出到打印设备上。包含该逻辑的上层类是Copy类,底层类是KeyboardReader和PrinterWriter。
在一个不好的设计中,上层类直接使用底层的类,在这种情况下,如果我们想要把输出定向到新的FileWriter类,就必须修改Copy类的代码(假设它是一个具有很多逻辑的复杂类并且很难测试)。
为了避免这种问题,我们可以在上层类和底层类之间引入一个抽象层。因为上层模块包含复杂的逻辑,所以它们不应该依赖于底层模块,新的抽象层也不应该基于底层模块而创建。底层模块应该基于抽象层而创建。
基于这个原则,设计类结构的方式应该是从上层模块到底层模块。
上层类--->抽象层--->底层类
依赖倒转原则
- 上层模块不应该依赖于底层模块,它们都应该依赖于抽象。
- 抽象不应该依赖于细节,细节应该依赖于抽象。
实例
下面是一个违反了依赖倒转原则的例子。我们有一个上层类Manager和底层类Worker。我们需要在程序中添加一个新模块,因为有新的特殊的工作者被雇用。为此,我们创建一个新的类SuperWorker。
我们假设Manager是一个包含非常复杂的逻辑的类,现在为了引入新的SuperWorker,我们需要修改它。让我们看一下这有哪些缺点:
- 我们需要修改Manager类(记住,它是一个非常复杂的类,这需要一些时间和努力)。
- Manager类的一些现有功能可能会受到影响。
- 需要重做单元测试。
所有的这些问题需要大量的时间去解决。但是如果程序的设计符合依赖倒转原则将会非常简单。意思是我们设计Manager类和一个IWorker接口以及一些实现了该接口的Worker类。当需要添加SuperWorker类时我们只需要让它实现IWorker接口。
-
-
class Worker {
-
public void work() {
-
- }
- }
-
-
class Manager {
- Worker m_worker;
-
-
public void setWorker(Worker w) {
- m_worker=w;
- }
-
-
public void manage() {
- m_worker.work();
- }
- }
-
-
class SuperWorker {
-
public void work() {
-
- }
- }
//Dependency Inversion Principle - Bad example
class Worker {
public void work() {
// ....working
}
}
class Manager {
Worker m_worker;
public void setWorker(Worker w) {
m_worker=w;
}
public void manage() {
m_worker.work();
}
}
class SuperWorker {
public void work() {
//.... working much more
}
}
下面是支持依赖倒转原则的代码。在这个新的设计中,我们增加了一个新的抽象层IWork接口。现在,上面的问题得到了解决:
- 不需要修改Manager类。
- 使对Manager类现有功能的影响最小化。
- 不需要对Manager类重新进行单元测试。
-
-
interface IWorker {
-
public void work();
- }
-
-
class Worker implements IWorker{
-
public void work() {
-
- }
- }
-
-
class SuperWorker implements IWorker{
-
public void work() {
-
- }
- }
-
-
class Manager {
- IWorker m_worker;
-
-
public void setWorker(IWorker w) {
- m_worker=w;
- }
-
public void manage() {
- m_worker.work();
- }
- }
//Dependency Inversion Principle - Good example
interface IWorker {
public void work();
}
class Worker implements IWorker{
public void work() {
// ....working
}
}
class SuperWorker implements IWorker{
public void work() {
//.... working much more
}
}
class Manager {
IWorker m_worker;
public void setWorker(IWorker w) {
m_worker=w;
}
public void manage() {
m_worker.work();
}
}
总结
应用该原则意味着上层类不直接使用底层类,他们使用接口作为抽象层。这种情况下上层类中创建底层类的对象的代码不能直接使用new操作符。可以使用一些创建型设计模式,例如工厂方法,抽象工厂和原型模式。
模版设计模式是应用依赖倒转原则的一个例子。
当然,使用该模式需要额外的努力和更复杂的代码,不过可以带来更灵活的设计。不应该随意使用该原则,如果我们有一个类的功能很有可能在将来不会改变,那么我们就不需要使用该原则。
分享到:
相关推荐
依赖倒转原则(Dependency Inversion Principle,DIP)是面向对象设计的基本原则之一,它在软件工程中扮演着至关重要的角色。这个原则主要是为了降低模块之间的耦合度,提高系统的可扩展性和可维护性。在C#编程语言...
面向对象设计原则总结 面向对象设计原则是软件设计中最重要的原则之一,它们是软件设计的基础和核心。面向对象设计原则的应用可以提高软件的开发效率、质量和可维护性。下面是七大面向对象设计原则的总结: 一、开...
对面向对象设计原则的总结,设计模式:“开-闭”原则,里氏代换原则、依赖倒转原则、合成/聚合复用原则、迪米特法则、接口隔离原则
面向对象设计原则概述 单一职责原则 开闭原则 里氏代换原则 依赖倒转原则 接口隔离原则 合成复用原则 迪米特法则
面向对象设计原则与设计模式是软件工程领域的重要组成部分,它们为构建高质量、可维护和可扩展的软件系统提供了指导方针。下面将详细阐述面向对象设计原则及其如何促进软件的复用,以及设计模式的概念。 ### 面向...
面向对象设计原则概述 单一职责 开闭原则 里氏代换原则 依赖倒转原则 接口隔离原则 合成复用原则 迪米特法则
面向对象编程的七大原则是指在面向对象设计中所遵循的七个基本原则,它们是:开闭原则、依赖倒转原则、单一职责原则、接口隔离原则、迪米特法则、里氏替换原则和组合优于继承原则。 1. 开闭原则(Open-Closed ...
依赖倒转原则(Dependency Inversion ...总结起来,依赖倒转原则是软件设计的重要指导原则,它提倡面向抽象编程,降低模块间的耦合,提高系统的灵活性。遵循这一原则,我们可以构建更加健壮、易于维护的软件系统。
面向对象设计原则是OOPS(Object-Oriented Programming System,面向对象的程序设计系统)编程的核心。在设计面向对象的程序的时,模式不是一定要套的,但是有一些原则最好是遵守。这些原则已知的有七个,包括:单一...
依赖倒转原则提倡“针对接口编程,而不是针对实现编程”。这意在降低模块间的耦合度,使得软件组件更加独立,易于测试和替换。通过依赖于抽象而非具体实现,系统可以更灵活地适应变化,提高复用性。 **分析与实践**...
面向对象设计原则概述 单一职责原则 开闭原则 里氏代换原则 依赖倒转原则 接口隔离原则 合成复用原则 迪米特法则
单一职责原则、开闭原则、里氏代换原则、依赖倒转原则、接口隔离原则、合成复用原则和迪米特法则相互补充,共同构成了面向对象设计的基石。理解并熟练应用这些原则,可以有效提高软件开发的效率,降低维护成本,实现...
在面向对象设计中,有七个基本原则,即单一职责原则、开闭原则、里氏代换原则、依赖倒转原则、接口隔离原则、合成复用原则和迪米特法则。 1. 单一职责原则(SRP):一个类只负责一个功能领域中的相应职责。单一职责...
详细介绍了: 单一职责原则 开闭原则 里氏代换原则 依赖倒转原则 接口隔离原则 合成复用原则 迪米特法则
面向对象设计原则是Java开发中不可或缺的指导方针,旨在提高软件的可维护性和可复用性。这些原则有助于创建更加灵活、稳定且易于扩展的系统。以下是对几个关键设计原则的详细阐述: 1. **单一职责原则 (Single ...
4. **依赖倒转原则(DIP)**:高层模块不应依赖于低层模块,两者都应依赖于抽象。抽象不应依赖于具体实现,具体实现应依赖于抽象。这通常通过使用接口或抽象类来实现,使得系统更易于维护和测试。 5. **接口隔离原则...
1面向对象6大原则--单一职责原则 2面向对象6大原则--里氏代换原则 3面向对象6大原则--开闭原则 4面向对象6大原则--依赖倒转原则 5面向对象6大原则--合成复用原则 6面向对象6大原则--接口隔离原则