C# 使用IoC容器的OOD-如何构造从属对象?
我正在努力改进IoC、DI和OOD,以获得更好的可测试性和更松散的耦合 因此,当我们设计大量使用IoC和DI的类时,我们最终可以得到具有多个依赖项的类C# 使用IoC容器的OOD-如何构造从属对象?,c#,oop,dependency-injection,inversion-of-control,autofac,C#,Oop,Dependency Injection,Inversion Of Control,Autofac,我正在努力改进IoC、DI和OOD,以获得更好的可测试性和更松散的耦合 因此,当我们设计大量使用IoC和DI的类时,我们最终可以得到具有多个依赖项的类 class Processor { private IService1 m_Service1; private IService2 m_Service2; private IService3 m_Service3; //approach 1 public Processor(IService1 serv
class Processor
{
private IService1 m_Service1;
private IService2 m_Service2;
private IService3 m_Service3;
//approach 1
public Processor(IService1 service1, IService2 service2, IService3 service3)
{
m_Service1 = service1;
m_Service2 = service2;
m_Service3 = service3;
}
//approach 2
public Processor(IContainer container)
{
m_Service1 = container.Resolve<IService1>();
m_Service2 = container.Resolve<IService2>();
m_Service3 = container.Resolve<IService3>();
}
//approach 3
public delegate Processor Factory();
}
现在我们创造
//approach 4
public Processor(ServiceLocatorObject servicesToUse)
{
m_Services = servicesToUse;
}
现在我们已经将我们的类与服务实现解耦,并明确了它需要什么样的真正依赖关系(如果我们假设所有在传递的对象上可用的服务都是必需的),因为我们传递的不是一个可以包含100个实现的容器。如果应用程序中的另一个类可能需要3个服务组合,那么该对象甚至可以重用。所以我们使用的是构造函数DI而不是ServiceLocator模式。接口是清晰的,并没有因依赖项而过载,新类可能是一个很好的重用候选者
关于这一点,你怎么看?这不是依赖项的数量,也不是每个类的决定。方法2引入了一个新的依赖项,但如果您想依赖IoC容器,那么这是一个好方法。方法3类似于第二种方法,但让我们将来在工厂里做一些事情。方法1最简单,不依赖任何东西,应该用于通常不会通过IoC容器管理的依赖项。现在,服务位置模式通常被认为是反模式(使用容器。解析并注入容器) 在我自己对这个概念进行了很多挣扎并试图决定我是喜欢它还是讨厌它之后,我个人意识到我同意服务位置是一种反模式——因为它混淆了存在的相互依赖关系,这是OOP的核心概念 请在此阅读: 实际上,我喜欢在选项1中,流程清楚地表达了它对它列出的每个服务的依赖性,这些服务都是构造函数中的参数。它使依赖性变得非常明显……而且我认为它有助于促进良好的设计
仅仅说处理器采用IContainer并不能告诉我们太多……因此,您需要更仔细地观察以确定相互依赖性。JeffN825给出的答案是正确的,但我想补充一点,您永远不会使用这样的容器创建新的处理器实例:
Processor proc = new Processor(
container.Resolve<IService1>(),
container.Resolve<IService2>(),
container.Resolve<IService3>());
Processor proc=新处理器(
container.Resolve(),
container.Resolve(),
container.Resolve());
相反,您应该让容器自动连接依赖项和:
Processor proc=container.Resolve();
这与依赖项的数量无关,也与每个类的决策无关。-你能详细说明一下吗?所以我们应该为整个应用程序选择单一的方法,并在任何地方使用它,或者你在说什么?我不知道为什么它不能是一个每类的决定..选择使用IoC容器会影响整个应用程序-每个模块都应该依赖它。方法1是自然的-所有开发人员都理解它。方法2是特定于容器的。你能做的最糟糕的事情就是把它们混在一起。代码的读者必须检查使用了哪种方法,测试的作者也是如此。link很好,那本书看起来正是我需要的。你觉得第三种方法怎么样?我在我的代码中都使用第三种方法…当我需要注入一种方法来创建一个类型的多个实例时。我使用Windsor…所以我经常使用代理工厂,当我知道我的处理器需要创建许多iSeries时,我会注入Func…谢谢你,Mark。你能谈谈第三种方法吗?当它比建议的处理器proc=container.Resolve()更好时,会出现什么情况;还是第一种方法?第三种方法只是一个伪装的抽象工厂:它与其他两种方法没有真正的联系。你会用它做什么?嘿,马克,在读了你的一些帖子后,我在问题中添加了一个更新,你对此有何看法?ServiceLocatorObject
做什么?我真的不能从提供的示例中判断,因为它没有任何行为?谢谢。从DI的角度来看,这很好。从一般的角度来看,这是一个参数对象。如果它们将相关概念组合在一起就可以了,但如果它们只在机械意义上使用就不行了。因此,我不能对这种方法的有效性给出任何一般性的答案,因为它取决于上下文。。。与参数对象密切相关的还有Facade服务(以前称为聚合服务):
public class ServiceLocatorObject
{
private IService1 m_Service1;
private IService2 m_Service2;
private IService3 m_Service3;
public IService1 Service1 {get {return m_Service1;}}
public IService2 Service2 {get {return m_Service2;}}
public IService3 Service3 {get {return m_Service3;}}
public ServiceLocatorObject(IService1 service1, IService2 service2, IService3 service3)
{
m_Service1 = service1;
m_Service2 = service2;
m_Service3 = service3;
}
}
//approach 4
public Processor(ServiceLocatorObject servicesToUse)
{
m_Services = servicesToUse;
}
Processor proc = new Processor(
container.Resolve<IService1>(),
container.Resolve<IService2>(),
container.Resolve<IService3>());
Processor proc = container.Resolve<Processor>();