9

我试图接受使用 IoC/依赖注入,同时对合同而不是特定类进行编程。我面临的困境是以下之间的紧张关系:

  1. 为 IoC 进行接口编程:我从 IoC 开始,严重依赖接口。从 Spring 的示例项目来看,接口是使用 IoC 进行合约编程时要走的路。

  2. ...虽然抽象类通常更受欢迎:接口的主要缺点是在允许 API 的演变方面,它们的灵活性远低于类

  3. 一定要通过构造函数显式地显示类依赖关系 我的直觉是,将依赖关系传递给类的构造函数是一种很好的编程习惯。实际上,这依赖注入。

  4. ...除非您不能在接口/抽象类中强制执行构造函数签名:接口或抽象类都不允许定义构造函数签名(轻松/优雅)。另请参阅框架设计指南第 4.4 节: 不要在抽象类型中定义公共或受保护的内部构造函数。...仅当用户需要创建该类型的实例时,构造函数才应该是公共的。

这个问题与之前的stackoverflow问题有关:定义构造函数签名的接口?

但我的问题是:

由于您不能在 C# 接口/抽象类中定义构造函数,正如上面的问题所问的那样,在实际层面上:

您如何将此与通过构造函数传递依赖项的明智做法相协调?

编辑:谢谢你的答案。我希望对在这种情况下我应该做什么有所了解。只是不使用构造函数参数?使用某种具有依赖关系的 Init() 方法?Edit2:感谢您的出色回答,非常有帮助。

4

3 回答 3

8

我一直认为用(编造的)例子更容易解释......

假设您有一个 ICustomerRepository 接口、一个 IShoppingCartRepository 接口和一个 ICheckout 接口。您有这些接口的具体实现 - CustomerRepository、ShoppingCartRepository 和 CheckoutService。

您的 CheckoutService 具体类有一个构造函数,它接受一个 ICustomerRepository 和一个 IShoppingCartRepository - 例如

public CheckoutService(ICustomerRepository customerRepository, IShoppingCartRepository shoppingCartRepository)
{
  // Set fields for use in some methods later...
  _customerRepository = customerRepository;
  _shoppingCartRepository = shoppingCartRepository;
}

然后,当您想要一个 ICheckoutService 实现来做一些工作时,您告诉您的 IoC 容器它应该为每种接口类型使用哪个具体类,并要求它为您构建一个 ICheckoutService。您的 IoC 容器将为您构建类,将正确的具体类注入到 CheckoutService 的构造函数中。它还将在此处的类层次结构中一直构建依赖关系,因此,例如,如果您的 ShoppingCartRepository 在构造函数中采用 IDatabaseSession 接口,那么您的 IoC 容器也会注入该依赖关系,只要您告诉它要使用哪个具体类为您的 IDatabaseService。

以下是您在配置(例如)StructureMap作为您的 IoC 容器时可能使用的一些代码(此代码通常在应用程序启动期间调用):

public class AppRegistry : Registry
{
  public AppRegistry()
  {
    ForRequestedType<ICheckoutService>().TheDefaultIsConcreteType<CheckoutService>();
    ForRequestedType<ICustomerRepository>().TheDefaultIsConcreteType<CustomerRepository>();
    // etc...
  }
}

然后,要建立一个 ICheckoutService 实例并准备好使用,并将所有依赖项传递给您的构造函数,您将使用如下内容:

var checkoutService = ObjectFactory.GetInstance<ICheckoutService>();

我希望这是有道理的!

于 2009-04-16T22:26:26.363 回答
1

您的 IoC 容器必须从具体类型构造一个对象,即使您传递的是一个接口。您的构造函数不是行为或状态契约,因此它不属于接口或抽象类的公共成员。

构造函数是一个实现细节,因此您不需要将其定义与具体类分开。

于 2009-04-16T15:06:53.343 回答
0

您不能在接口中定义构造函数签名。无论如何,这没有任何意义,因为接口不应该强制执行实现的构造方式。

抽象类虽然确实可以有构造函数。它们必须受到保护,因为公共构造函数也没有意义。它们只能由具体的子类调用。

IoC 原则规定,与其让 A 类知道并实例化 B 类,不如将对 IB 的引用传递给 A 的构造函数。然后 A 不需要知道 B 类,因此您可以轻松替换 B 类与 IB 的其他一些实现。

由于您要传入 B 类的已实例化对象,因此 IB 接口不需要具有构造函数签名。

于 2009-04-16T15:07:58.097 回答