当调用者期望特定的构造函数签名时使用构造函数注入
Using constructor injection when caller expects a specific constructor signature
我是 .NET C# 和 autofac 中的 DI 的新手,当我无法完全控制调用方时,我很难理解如何使用 DI。
有两种情况我很难理解。
场景 1:调用方需要默认构造函数(不带任何参数)
构造class的时候还想注入一些Service Interface怎么办?我在考虑构造函数链接,但这意味着我必须知道具体类型并且它围绕 DI 的想法工作。 (至少我认为)。
public class ServiceWorker
{
IService _service;
public ServiceWorker(IService service)
{
_service = service
}
}
public class Caller
{
// No way to change this.
var serviceWorker = new ServiceWorker();
}
场景 2:调用方需要特定的构造函数签名(例如
同样的问题。当调用者期望构造函数签名完全匹配时,如何注入额外的依赖项?
我认为我理解这个概念的主要问题是,当并非所有内容都由 DI(调用者)构建时,我看不到如何仅部分地执行 DI
public class ServiceWorker
{
IService _service;
public ServiceWorker(string name, string id, IService service)
{
_service = service
}
}
public class Caller
{
// No way to change this.
var serviceWorker = new ServiceWorker(name, id);
}
我知道,这是非常基础的,但我相信在继续之前我需要先了解这一点。有其他选择吗?
正如 Steven 在他的评论中正确指出的那样,仅限于特定的构造函数签名是 Constrained Construction 反模式的一个实例。然而,有时这可能超出了您的控制范围。
一个例子是so-called 'Provider pattern', which isn't a pattern at all。在这样的示例中,您可能必须遵守第三方框架的规则,因此您无能为力。这样的框架应该被认为对依赖注入不友好。
考虑 OP 中的场景 2,因为场景 1 只是场景 2 的特例。如果您 必须 提供具有特定构造函数的 class,您可以创建具有所需构造函数签名的 Facade。这使您能够避免使用第三方框架施加的约束污染使用依赖注入的精心设计的 classes。它可能看起来像这样:
public class ServiceWorker
{
IService _service;
public ServiceWorker(string name, string id, IService service)
{
_service = service
}
}
public class ServiceWorkerFacade
{
ServiceWorker imp;
public ServiceWorkerFacade(string name, string id)
{
imp =
new ServiceWorker(
name,
id,
new FooService(
new BarService(),
new BazService());
}
}
public class Caller
{
// No way to change this.
var serviceWorker = new ServiceWorkerFacade(name, id);
}
FooService
实施 IService
。只是为了让事情变得有趣,我假设 FooService
有自己的依赖关系,并且 BarService
和 BazService
.
满足这些依赖关系
正如 Steven 所建议的那样,您可以(出于必要)将 Facade 的构造函数视为 Composition Root。
如果您有任何机会影响相关框架的设计,您可以向开发人员指出 my guidance on designing DI-friendly frameworks。
我是 .NET C# 和 autofac 中的 DI 的新手,当我无法完全控制调用方时,我很难理解如何使用 DI。
有两种情况我很难理解。
场景 1:调用方需要默认构造函数(不带任何参数)
构造class的时候还想注入一些Service Interface怎么办?我在考虑构造函数链接,但这意味着我必须知道具体类型并且它围绕 DI 的想法工作。 (至少我认为)。
public class ServiceWorker
{
IService _service;
public ServiceWorker(IService service)
{
_service = service
}
}
public class Caller
{
// No way to change this.
var serviceWorker = new ServiceWorker();
}
场景 2:调用方需要特定的构造函数签名(例如
同样的问题。当调用者期望构造函数签名完全匹配时,如何注入额外的依赖项?
我认为我理解这个概念的主要问题是,当并非所有内容都由 DI(调用者)构建时,我看不到如何仅部分地执行 DI
public class ServiceWorker
{
IService _service;
public ServiceWorker(string name, string id, IService service)
{
_service = service
}
}
public class Caller
{
// No way to change this.
var serviceWorker = new ServiceWorker(name, id);
}
我知道,这是非常基础的,但我相信在继续之前我需要先了解这一点。有其他选择吗?
正如 Steven 在他的评论中正确指出的那样,仅限于特定的构造函数签名是 Constrained Construction 反模式的一个实例。然而,有时这可能超出了您的控制范围。
一个例子是so-called 'Provider pattern', which isn't a pattern at all。在这样的示例中,您可能必须遵守第三方框架的规则,因此您无能为力。这样的框架应该被认为对依赖注入不友好。
考虑 OP 中的场景 2,因为场景 1 只是场景 2 的特例。如果您 必须 提供具有特定构造函数的 class,您可以创建具有所需构造函数签名的 Facade。这使您能够避免使用第三方框架施加的约束污染使用依赖注入的精心设计的 classes。它可能看起来像这样:
public class ServiceWorker
{
IService _service;
public ServiceWorker(string name, string id, IService service)
{
_service = service
}
}
public class ServiceWorkerFacade
{
ServiceWorker imp;
public ServiceWorkerFacade(string name, string id)
{
imp =
new ServiceWorker(
name,
id,
new FooService(
new BarService(),
new BazService());
}
}
public class Caller
{
// No way to change this.
var serviceWorker = new ServiceWorkerFacade(name, id);
}
FooService
实施 IService
。只是为了让事情变得有趣,我假设 FooService
有自己的依赖关系,并且 BarService
和 BazService
.
正如 Steven 所建议的那样,您可以(出于必要)将 Facade 的构造函数视为 Composition Root。
如果您有任何机会影响相关框架的设计,您可以向开发人员指出 my guidance on designing DI-friendly frameworks。