【问题标题】:Clarification on understanding of "Dependency Inversion"澄清对“依赖倒置”的理解
【发布时间】:2015-04-24 04:54:01
【问题描述】:

在上面查找后,我发现的大部分答案是这样的:

  • 高级模块不应依赖于低级模块。两个都 应该依赖于抽象。
  • 抽象不应该依赖于 根据细节。细节应该取决于抽象。

我的理解是这样的设计违反了?因为类 Car 依赖于较低级别的类 Engine

public class Car {
    private Engine engine;

    public void run() {
        engine.start()
       // do other stuff
    }
}

public class Engine {
    public void start() {
         // do stuff that will start engine
    }
}

如果确实违反了,解决办法是什么?我想不出替代方案。

我也很难理解第二部分“抽象不应该依赖于 根据细节。细节应该取决于抽象。”

【问题讨论】:

    标签: java oop design-patterns solid-principles


    【解决方案1】:

    下面的链接很好地解释了依赖倒置的概念: http://www.oodesign.com/dependency-inversion-principle.html

    基本上,它归结为取决于简单类的行为的复杂类,而不是类本身。在您的示例中,以下将是依赖倒置的良好实现:

    interface Movable {
        public void start();
        public void throttleUp();
        public void throttleDown();
        //etc..
    }
    
    class Engine implements Movable {
        public void start() {
            //code
        }
        //implement other methods
    }
    
    class Car {
        Movable engine;
    
        public void setEngine(Movable engine) {
            this.engine = engine;
        }
    
        public void run() {
            engine.start();
            //code...
        }
    }
    

    将来您可以制造不同类型的发动机,例如汽油、柴油、蒸汽、电动。但是只要他们实现了Movable,你的Car就不会因为解耦而改变。

    【讨论】:

      【解决方案2】:

      你需要了解运行时依赖和代码依赖的区别。 Car 将始终对您的 Engine 实现细节有运行时依赖,因为控制流将从 Car 转移到 Engine。

      然而,依赖倒置是关于源代码依赖的。您可以使 Engine 成为接口或抽象类,并且不同的子类可以提供自己的 start() 实现(多态性)。这样,您的 Car 将仅依赖于 Engine 抽象(在源代码级别),而不依赖于各种 start() 实现的细节。 Car 被编写、编译和部署之后,您可以向系统添加新引擎。

      另请注意,这些原则更像是建议,而不是“总是/从不”规则。使用您自己的判断。

      【讨论】:

      • 关于您回复的“规则”部分的注释:Dependency Inversion 是 SOLID 范例的一部分,因此如果您想编写 SOLID 代码,则必须遵循这些规则。
      • @Cristik 好吧,我不想写“SOLID 代码”。我想编写好的代码,虽然“SOLID”原则是好的指导方针,但它们有时会与 KISS 和 YAGNI 等其他好的指导方针相矛盾。
      • 我不认为 SOLID、KISS 和 YAGNI 是相互排斥的,它们针对不同的方面。 SOLID 处理健壮的代码,YAGNI 处理臃肿但正确的代码,而 KISS 处理可能变得复杂的代码。你可以尊重所有三个(尽管我必须说我发现很难只遵循其中一个:)
      • @Cristik 在开始为每个类定义接口之前,您应该阅读此问题的答案:programmers.stackexchange.com/questions/159813/…
      • 我没有说我会为每个类定义一个接口:)
      【解决方案3】:

      让我重新表述你帖子中已经存在的所有内容,看看是否有意义

      1. Car 完全可以像您的情况一样依赖 Engine 的接口(只要注入了 Engine)。
      2. 像 Car 这样的高级模块不应依赖于低级实现细节 - 比如说 Engine 的特定子类,例如JetEngine 但是依赖于接口Engine也可以
      3. Engine 之类的抽象不应依赖于任何特定的实现(再说一次 Nut、Bolt 或 Engine 的子类)。

      【讨论】:

        猜你喜欢
        • 2017-09-09
        • 1970-01-01
        • 1970-01-01
        • 2011-09-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-20
        • 1970-01-01
        相关资源
        最近更新 更多