没有服务定位器的 IOC
IOC without Service Locator
假设我有 3 个 类、Program
、A
(具有依赖项 D1
和 D2
)和 B
(具有依赖项D3
和 D4
)。 Program
在创建 A
.
的实例之前初始化一个 IOC 容器并注册一堆类型
class Program
{
static void Main(string[] args)
{
IOC ioc = new IOC();
//register types
A a = ioc.Resolve<A>();
}
}
稍后,a
需要创建 B
的实例,将其两个依赖项注入构造函数。
问题:a
应该如何解决B
的依赖?我被引导相信传递 IOC 容器,即将它注入 A
是服务定位器模式,这是不好的。如果 B
创建了 C
及其依赖项, B
也需要注入容器,并且容器会在我的代码中乱七八糟。这听起来像是一场测试噩梦。使用全局静态听起来并没有好多少。
理想情况下,您永远不应将容器注入 classes 只是为了解决依赖关系。相反,你在单独的地方注册实例可能是你的启动 class 在运行时应用程序应该能够从容器中注册的实例自动解决依赖关系。
查看以下示例 IOC 容器通常如何注册其实例
注册
SimpleIoc.Default.Register< IDataService, DataService >();
SimpleIoc.Default.Register< MainViewModel >();
SimpleIoc.Default.Register< SecondViewModel >();
解决
SimpleIoc.Default.GetInstance< MainViewModel >();
其实很简单。如果 A
需要 B
,它应该接受 B
作为构造函数参数:
public class A
{
private readonly D1 d1;
private readonly D2 d2;
private readonly B b;
public A(D1 d1, D2 d2, B b) {
this.d1 = d1;
this.d2 = d2;
this.b = b;
}
}
public class B
{
private readonly D3 d3;
private readonly D4 d4;
private readonly C c;
public B(D3 d3, D4 d4, C c) {
this.d3 = d3;
this.d4 = d4;
this.c = c;
}
}
通过这种方式递归地构建对象图,您可以获得非常深的对象图,这完全没问题。这样你只需要应用程序启动路径中的容器(a.k.a。组合根)。
是否 A
需要 B
'later on',或者只是有时,或者几乎从不,这无关紧要。构建对象图应该很快,因此是否不必要地创建 B
应该不是问题。
At some point later on, A
needs to create an instance of 'B',
injecting its two dependencies into the constructor.
在这种情况下,A
必须依赖于可以为其创建 B
的 BFactory
。
假设我有 3 个 类、Program
、A
(具有依赖项 D1
和 D2
)和 B
(具有依赖项D3
和 D4
)。 Program
在创建 A
.
class Program
{
static void Main(string[] args)
{
IOC ioc = new IOC();
//register types
A a = ioc.Resolve<A>();
}
}
稍后,a
需要创建 B
的实例,将其两个依赖项注入构造函数。
问题:a
应该如何解决B
的依赖?我被引导相信传递 IOC 容器,即将它注入 A
是服务定位器模式,这是不好的。如果 B
创建了 C
及其依赖项, B
也需要注入容器,并且容器会在我的代码中乱七八糟。这听起来像是一场测试噩梦。使用全局静态听起来并没有好多少。
理想情况下,您永远不应将容器注入 classes 只是为了解决依赖关系。相反,你在单独的地方注册实例可能是你的启动 class 在运行时应用程序应该能够从容器中注册的实例自动解决依赖关系。
查看以下示例 IOC 容器通常如何注册其实例
注册
SimpleIoc.Default.Register< IDataService, DataService >(); SimpleIoc.Default.Register< MainViewModel >();
SimpleIoc.Default.Register< SecondViewModel >();
解决
SimpleIoc.Default.GetInstance< MainViewModel >();
其实很简单。如果 A
需要 B
,它应该接受 B
作为构造函数参数:
public class A
{
private readonly D1 d1;
private readonly D2 d2;
private readonly B b;
public A(D1 d1, D2 d2, B b) {
this.d1 = d1;
this.d2 = d2;
this.b = b;
}
}
public class B
{
private readonly D3 d3;
private readonly D4 d4;
private readonly C c;
public B(D3 d3, D4 d4, C c) {
this.d3 = d3;
this.d4 = d4;
this.c = c;
}
}
通过这种方式递归地构建对象图,您可以获得非常深的对象图,这完全没问题。这样你只需要应用程序启动路径中的容器(a.k.a。组合根)。
是否 A
需要 B
'later on',或者只是有时,或者几乎从不,这无关紧要。构建对象图应该很快,因此是否不必要地创建 B
应该不是问题。
At some point later on,
A
needs to create an instance of 'B', injecting its two dependencies into the constructor.
在这种情况下,A
必须依赖于可以为其创建 B
的 BFactory
。