C# IoC容器:创建的实例的结构略有不同
我正在学习IoC、DDD和AOP概念。我读过很多文章、文档、Ninject手册(我只限于使用.NET3.5)、尝试过一些东西等等 很难一下子把所有事情都想清楚,但动机、概念和技术问题都有点清楚。我一直觉得我错过了什么 首先,据我所知,IoC容器的目的是建立初始对象结构吗 比如,在composition根目录中设置容器,创建“main”对象,该对象一直由IoC容器连接 那么,据我所知,以后所有的对象都是用工厂实例化的?尽管我无法控制自己将工厂视为服务定位器的一个案例(最终被认为是反模式的,顺便说一句,它被用作IoC容器的核心机制) 因此,问题是: 如果我想创建一个结构稍有不同的实例,例如C# IoC容器:创建的实例的结构略有不同,c#,dependency-injection,inversion-of-control,factory,C#,Dependency Injection,Inversion Of Control,Factory,我正在学习IoC、DDD和AOP概念。我读过很多文章、文档、Ninject手册(我只限于使用.NET3.5)、尝试过一些东西等等 很难一下子把所有事情都想清楚,但动机、概念和技术问题都有点清楚。我一直觉得我错过了什么 首先,据我所知,IoC容器的目的是建立初始对象结构吗 比如,在composition根目录中设置容器,创建“main”对象,该对象一直由IoC容器连接 那么,据我所知,以后所有的对象都是用工厂实例化的?尽管我无法控制自己将工厂视为服务定位器的一个案例(最终被认为是反模式的,顺便说一
interface IFoo{}
interface IBar{}
class SomeClass
{
SomeClass(IFoo obj){...}
}
class Foo : IFoo
{
Foo(IBar obj){...}
}
class Bar : IBar
{
}
class FooBar : IBar // also implements IBar interface
{
}
因此,初始绑定配置是创建SomeClass.Foo.Bar
结构。假设,我还需要SomeClass.Foo.FooBar
。我该怎么办?我能想到的选择是:
- “就地”重新配置绑定:仅此而已
- 为顶级类提供一个构造函数参数,该参数具有整个结构的配置。那太可怕了。除了所有后续构造函数(以及所有其他项目类构造函数,我确信最终)都必须有一个额外的参数之外,还没有清楚地看到它将如何工作,并且没有使用一些肮脏的技巧
- 替换创建对象后所需的内容。它要么违反了德墨忒尔定律(对此我不太关心,但在这种情况下,它太粗鲁了)和其他一些原则,要么,在一般情况下,根本不可能
- 使用以某种方式配置的工厂。它只是将需求本身延迟/转移到代码中的稍后/其他位置
- 使用某种上下文/常规绑定。我看到的一个解决方案(还没有测试)是一直到“激活根”的顶部,检查是什么创建了层次结构。m、 我们必须为顶级类制作装饰器,以便容器检查其类型并相应地进行操作。实际上,容器可以通过一种方式进行配置,即它通过“解析”顶级接口的名称来决定注入哪个具体实例。差不多 ICfg_混凝土类型1_混凝土类型2_
或者我们可以使用属性来设置它。或者可能是我不知道什么。您通常会使用某种标签系统
您通常会使用某种标签系统
您通常会使用某种标签系统
您通常会使用某种标签系统 首先,据我所知,IoC容器的目的是建立初始对象结构吗 暂时忘掉IoC容器吧。依赖注入与使用工具无关。它首先是关于应用原则和模式的。依赖注入背后的驱动力是坚实的原则。我甚至可以在不使用IoC容器的情况下启动您的应用程序,并且只有在真正有理由这样做时才开始使用IoC容器。这意味着您只需手动构建对象图。这样做的正确位置是在作文的根目录中。这应该是组成对象图的单一位置 请注意,这个建议来自于他自己 那么,据我所知,以后所有的对象都是用工厂实例化的 在实践依赖注入时,您将看到使用工厂的需求实际上最小化了。它们仍然是有用的,但我现在只是很少使用它们 原因是工厂通常只添加一个额外的(无用的)抽象层 当开始使代码更松散耦合时,开发人员倾向于使用工厂,如下所示:
public class SomeClass
{
public void HandleSomething() {
IFoo foo = FooFactory.Create();
foo.DoSomething();
}
}
public class SomeClass
{
private readonly IFooFactory fooFactory;
public SomeClass(IFooFactory fooFactory) {
this.fooFactory = fooFactory;
}
public void HandleSomething() {
IFoo foo = this.fooFactory.Create();
foo.DoSomething();
}
}
new SomeClass(
new Foo(
new Bar()));
new SomeClass(
new Foo(
new BarProxy(
new Bar(),
new FooBar()));
public class BarProxy
{
private readonly IBar left;
private readonly IBar right;
public BarProxy(IBar left, IBar right) {
this.left = left;
this.right = right;
}
public void BarMethod(BarOperation op) {
this.GetBar(op).BarMethod(op);
}
private IBar GetBar(BarOperation op) {
return op.SomeValue ? this.left : this.right;
}
}
尽管这允许Foo
实现与SomeClass
解耦,SomeClass
仍然强烈依赖FooFactory
。这仍然使得SomeClass
难以测试,并降低了可重用性
遇到这样的问题后,开发人员通常开始抽象FooFactory
类,如下所示:
public class SomeClass
{
public void HandleSomething() {
IFoo foo = FooFactory.Create();
foo.DoSomething();
}
}
public class SomeClass
{
private readonly IFooFactory fooFactory;
public SomeClass(IFooFactory fooFactory) {
this.fooFactory = fooFactory;
}
public void HandleSomething() {
IFoo foo = this.fooFactory.Create();
foo.DoSomething();
}
}
new SomeClass(
new Foo(
new Bar()));
new SomeClass(
new Foo(
new BarProxy(
new Bar(),
new FooBar()));
public class BarProxy
{
private readonly IBar left;
private readonly IBar right;
public BarProxy(IBar left, IBar right) {
this.left = left;
this.right = right;
}
public void BarMethod(BarOperation op) {
this.GetBar(op).BarMethod(op);
}
private IBar GetBar(BarOperation op) {
return op.SomeValue ? this.left : this.right;
}
}
这里使用了IFooFactory
抽象,它是使用构造函数注入注入的。这允许SomeClass
完全松耦合
SomeClass
但是现在有两个外部依赖项。它既知道IFooFactory
又知道IFoo
。这重复了SomeClass
的复杂性,但没有令人信服的理由这样做。在编写单元测试时,我们会立即注意到复杂性的增加。我们现在将突然不得不模拟两种不同的行为,并对它们进行测试
因为我们在这里练习构造函数注入,所以我们可以简化SomeClass
——没有任何缺点——如下所示:
public class SomeClass
{
private readonly IFoo foo;
public SomeClass(IFoo foo) {
this.foo = foo;
}
public void HandleSomething() {
this.foo.DoSomething();
}
}
长话短说,尽管Factory设计模式仍然有效和有用,但您几乎不需要它来检索
尽管我无法控制自己将工厂视为服务定位器的一个案例
不可以。工厂不是服务定位器。工厂和定位器之间的区别在于,使用工厂只能构建一种特定类型的对象,而l