使用IoC容器的OOD - 如何构建依赖对象?

时间:2011-08-13 03:56:17

标签: 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 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();

}

我在想这里应该采用什么方法。我们可以给构造函数留下3个参数,但是如果我们使用autofac构建应用程序(例如),很可能除了从某个容器实例中解析类型之外很少使用它,比如

    Processor proc = new Processor(
 container.Resolve<IService1>(),
 container.Resolve<IService2>(),
 container.Resolve<IService3>());

所以当我们依赖容器中的多种类型时,我想也许方法2更好。无论如何,我们必须在某个地方添加autofac的引用,所以现在有任何理由不这样做吗?

Autofac还提供委托工厂方法方法

http://code.google.com/p/autofac/wiki/DelegateFactories

var processorFactory = container.Resolve<Processor.Factory>();
Processor processor = processorFactory.Invoke();

所以我们也接近3 - 我们不会使用构造函数来创建我们的类实例,而是我们将从容器中调用已解析的委托,它将解决我们的依赖关系。

由于我对IoC很新,很难说我们何时应该使用1,2,3。它们各有利弊。

我认为一般来说,如果类有1依赖,我们可能总是使用方法1 ..除此之外,我真的不确定选择什么以及什么时候。

更新我已阅读有关服务定位器反模式但我已提出第4(或真正的第3种方法)

它接近ServiceLocator,除了它没有,我们传递一个看起来像这样的对象

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;
}

现在我们已经将我们的类与服务实现分离,并清楚它需要什么样的真实依赖项(如果我们假设所有服务都需要传递对象),因为我们没有传递一个可以包含100个实现的容器。如果在我们的应用程序中的某个另一个类中可能需要该3个服务组合,那么该对象甚至可以被重用。所以我们使用构造函数DI而不是ServiceLocator模式。接口是清晰的,没有重载依赖,新类可能是一个很好的重用候选者。

你对这个怎么说?

3 个答案:

答案 0 :(得分:6)

服务地点模式现在通常被认为是反模式(使用container.Resolve和注入容器)。

在我自己努力解决这个概念并试图决定我是喜欢它还是讨厌它之后,我逐渐认识到我同意服务位置是一种反模式 - 因为它模糊了存在的相互依赖关系是OOP的核心概念。

请阅读: http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx

实际上,我认为在选项1中,Process CLEARLY表示它对列出的每个服务的依赖关系是构造函数中的参数。它使依赖性非常明显......而且我认为它有助于促进良好的设计。

只是说处理器需要一个IContainer并没有告诉我们什么......因此你需要仔细看看以确定相互依赖性。

答案 1 :(得分:6)

JeffN825给出的答案是正确的,但我想补充一点,你永远不会使用像这样的容器创建一个新的Processor实例:

Processor proc = new Processor(
    container.Resolve<IService1>(),
    container.Resolve<IService2>(),
    container.Resolve<IService3>());

相反,您可以让容器自动连接依赖项和resolve it one go

Processor proc = container.Resolve<Processor>();

答案 2 :(得分:0)

这不是关于依赖的数量,也不是每个类的决定。方法2引入了一个新的依赖项,但是如果你想依赖一个IoC容器,那么这是一个很好的方法。方法3就像第二种方法,但是让你今后在工厂做一些事情。方法1最简单,不依赖任何东西,应该用于通常不通过IoC容器管理的依赖项。