为什么使用接口而不是抽象类与DI?

为什么使用接口而不是抽象类与DI?

问题描述:

我开始学习有关依赖注入的旅程,并且我看到为什么使用DI是一个好主意的原因之一是它明确指定了依赖关系,这也使得您的代码更清晰。为什么使用接口而不是抽象类与DI?

我也注意到接口被大量使用,但我想知道为什么我们不会使用抽象类来指定默认构造函数的唯一目的?

当然,抽象类中不能包含任何实现。

这岂不:

abstract class FooBase 
{ 
    protected IBar _bar; 

    FooBase(IBar bar) 
    { 
     _bar = bar; 
    } 

    abstract void DoSomething(); 
    abstract void DoSomethingElse(); 
} 

演示更清楚什么是FooBase对象的依赖超过:

interface IFoo 
{ 
    IBar Bar { get; } 

    void DoSomething(); 
    void DoSomethingElse(); 
} 

请记住我是新来这整个概念就这样好:)

+6

接口更灵活,因为任何类都可以实现额外的接口。但是任何给定的类只能有一个基类。 – 2012-07-19 21:24:12

+1

为什么“抽象类没有实现”? – 2012-07-19 21:24:16

+0

@AustinSalonen我相信,因为有了DI,我们希望促进“松耦合”和易于测试。在抽象类中的实现会使换出其他逻辑不同于抽象类的对象变得困难。 – ChandlerPelhams 2012-07-19 21:26:06

一个技术原因 - 迫使语言特别是父类没有多重继承(Java/C#)将显著限制执行的*“接口”。

注意,有2个概念背后隐藏的“接口”字,它有点使它更难原因,在C#:

  • “接口”和抽象的概念:良好定义的一组属性/方法进行互动与一个对象;合同与对象一起工作。
  • “interface”作为特定语言中的类型(C#/ Java) - 给定语言中 合同的一种可能表示形式。

抽象/具体类可以用来表示契约,但是强制对C#中契约实现者的限制。

其他一些语言(如C++)没有这种限制,抽象类是很好的选择。其他语言(即“鸭型”JavaScript)没有这样的类/接口区分,但您仍然可以与对象“签约”。

样品:

为了提供更多的情况下,你应该打这个限制自己在C#:DI通常与某种形式的TDD或至少与基本的单元测试一起使用。所以你可以尝试编写一些使用抽象基类的代码和测试。

abstract class Duck { 
    abstract void Quack(); 
} 
class ConcreteDuck : Duck {...} 

现在,如果你决定写测试,你可能已经有了测试类,可以帮助你嘲笑的对象(如果你不使用现有的一次)

class MockBase {...} 

class MockDuck : MockBase,?????? // Can't use Duck and MockBase together... 

接口定义的合同。抽象基类定义了一个行为。从本质上讲,你可以提供一个实现多个接口的类,即 ,然后它可以被注入到多个类中,但是只有一个抽象基类(至少在C#中)有 的 。

考虑在容器(组合根最好)注册类型 并考虑解决依赖关系(构造函数或属性)的问题。

这将SO覆盖更多一些方面SO on interface vs base class

在.NET中,只有单继承。在这种情况下的语言/框架中,选择使用抽象类作为您的抽象可以提供"burn the base class"的潜力。

这意味着您强制抽象的实现者从单数类继承,强迫他们这样做时可能会导致严重不方便,这取决于实现是什么。

假设你有你的抽象类Contract。如果某人有自己想要使用的Base类,那么只会暴露protected方法(用于继承者)。

,因为这些方法都是protected,一个不能用封装(存储在一个领域Base实例)访问Base方法为您抽象的实现。

更糟糕的是,如果您无权修改Base,那么您可能不得不采取一些非常丑陋的解决方法(即反射)。

这就是说,通过接口,您可以让实施者选择从哪里继承,并且不会限制他们的选择。

您将看到的典型模式是您始终为您的合同提供一个界面,并根据界面为您的客户编写代码。您提供的也是提供了一个抽象基类,它提供了人们为了方便而从派生的功能,但不是义务派生自。另外,如果你可能以某种容易被封装的东西(对于我上面描述的条件)来提供这个功能,它会更加优化(你会有一个抽象类,它只是调用暴露方法的实例)。