依赖倒置原则与“编程到接口而不是实现”


12

我试图了解依赖倒置原则与“程序到接口,而不是实现”原则的区别。

我了解“对接口编程,而不是实现”的含义。我也了解它如何允许更灵活和可维护的设计。

但是我不理解依赖关系反转原理与“程序到接口,而不是实现”原理有何不同。

我在网上的几个地方都读到了DIP,但这并没有消除我的困惑。我仍然看不到这两个原则之间的区别。谢谢你的帮助。

Answers:


25

“编程到接口”意味着不依赖于具体的类型来完成工作,但未指定如何获取依赖项。

“依赖关系反转原理”说,一个对象不应该控制其依赖关系的创建,它应该只是通告它需要什么依赖关系,并让调用者提供它。但是它没有指定依赖关系是具体类型还是接口。

我将用一些C#代码来说明这些差异。

下面的示例取决于具体的类型,它控制着它自己的依赖项的创建。它既不遵循“程序到接口”也不遵循“依赖倒置”:

public class ThingProcessor
{
    MyThing _myThing;

    public ThingProcessor()
    {
        _myThing = new MyThing();
    }

    public void DoSomething()
    {
        _myThing.DoIt();
    }
}

下面的示例取决于一个接口,但是它控制着它自己的依赖关系的创建。它遵循“程序到接口”,但不遵循“依赖关系倒置”:

public class ThingProcessor
{
    IMyThing _myThing;

    public ThingProcessor()
    {
        _myThing = ThingFactory.GiveMeANewMyThing();
    }

    public void DoSomething()
    {
        _myThing.DoIt();
    }
}

下面的示例取决于具体的类型,但是它要求创建其依赖项并将其传递给它。它遵循“依赖倒置”,但不遵循“编程到接口”:

public class ThingProcessor
{
    MyThing _myThing;

    public ThingProcessor(MyThing myThing)
    {
        _myThing = myThing;
    }

    public void DoSomething()
    {
        _myThing.DoIt();
    }
}

下面的示例取决于一个接口,它要求创建其依赖关系并将其传递给它。它同时遵循“依赖倒置” “编程到接口”:

public class ThingProcessor
{
    IMyThing _myThing;

    public ThingProcessor(IMyThing myThing) // using an interface
    {
        _myThing = myThing;
    }

    public void DoSomething()
    {
        _myThing.DoIt();
    }
}

1
差异的出色例证。
罗里·亨特

8
您正在谈论的是依赖皮下注射。依赖倒置和依赖注入是两个不同的东西。
欣快2014年

1
@Euphoric我正在谈论依赖倒置原则,这是一个抽象概念,通过使用依赖注入作为具体的实现示例。我了解不同之处。
埃里克·金

1
@EricKing然后,您应该在答案中明确说出这一点,而不是去““依赖倒置原则”说……”,如果您阅读我的答案,显然是错误的。
欣快2014年

1
我同意欣快。依赖倒置原则说,较高级别的代码层应取决于较低级别的代码段,而不是相反。例如,PrintStream应取决于所建立的接口ByteOutputStream。依赖注入没有提及谁应该依赖谁。
2014年

5

他们通常是同一回事。如果您阅读什么是依赖倒置原则,为什么重要呢?Dependency Inversion Principle,您将认识到两个“原理”基本上是关于同一件事的。

  • 高级模块不应依赖于低级模块。两者都应依赖抽象。
  • 抽象永远不要依赖细节。细节应取决于抽象。

接口是一个抽象,实现是一个细节。如果将它们替换为前两个语句,则基本上会得到“代码应取决于接口而不是实现”。对我来说,这听起来是一样的。


这应该是公认的答案,另一个投票最多的答案是令人误解的
Sameh Deabes

2

接口是实现DI的一种方法。如果在类的构造方法中将接口指定为参数,则可以将喜欢的任何对象交给该构造方法,只要该对象实现构造函数参数的接口即可。

换句话说,对接口进行编程可以使您 更改该接口的实现。这样,我们就能在单元测试期间用模拟对象代替真实对象,指定不同的数据提供者,等等。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.