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

发布于 2024-11-29 12:23:10 字数 2702 浏览 1 评论 0原文

我正在努力改进 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.. 除此之外,我真的不确定选择什么以及何时选择。

更新 我已经阅读了有关服务定位器反模式的内容,但我想出了第四种(或真正的第三种方法),

它接近 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 模式。接口清晰并且没有过多的依赖项,新类可能是一个很好的重用候选者。

对于这个你有什么想说的呢?

I am trying to get better with IoC,DI and OOD for better testability and looser coupling.

So when we design classes with heavy use of IoC and DI we can endup with classes with multiple dependencies for example

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();

}

Im thinking what should be the usual approach here. We can leave constructor with 3 parameters, but if we are building app using autofac (for example) most likely it will rarely be used other than by resolving types from some container instance like

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

so I am thinking maybe approach 2 is better, when we depend on multiple types from container. Anyway we will have to add reference to autofac somewhere, so any reasons not to do it now?

Autofac also provides delegate factory method approach

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

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

So we have also approach 3 - we will not use constructors to create our class instances, instead we will be calling resolved delegate from container and it will resolve dependencies for us.

Since im fairly new to IoC its hard to say when we should use 1,2,3. They have advantages and disadvantages.

I think generally if class has 1 dependency we can probably always use approach 1.. other than that I am really not sure what to choose and when.

UPDATE i have read about service locator anti pattern but Ive come up with 4th (or true 3rd approach)

its close to ServiceLocator except its not, we pass an object that looks like this

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

And now we create

//approach 4
public Processor(ServiceLocatorObject servicesToUse)
{
    m_Services = servicesToUse;
}

Now we have decoupled our class from service implementations and its clear what real dependencies it needs (if we assume all services availabe on passed object are required) because we aren't passing a container that can contain 100 implementations. And that object can be even reused if that 3 service combination might be required in some another class in our application. So we are using constructor DI not ServiceLocator pattern. interface is clear and not overloaded with dependencies, new class might be a good reuse candidate.

What would you say about this one?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一笑百媚生 2024-12-06 12:23:10

如今,服务位置模式通常被认为是反模式(使用container.Resolve并注入容器)。

在我自己对这个概念进行了一番挣扎并试图决定我喜欢它还是讨厌它之后,我个人意识到我同意服务位置是一种反模式 - 因为它混淆了存在的相互依赖关系,而这些相互依赖关系是核心面向对象编程的概念。

在这里阅读:
http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx

我实际上喜欢这样一个事实:在选项 1 中,Process 清楚地表达了它对其列出的每个服务的依赖关系:构造函数中的参数。它使依赖性非常明显......而且我认为它有助于促进良好的设计。

仅仅说 Processor 采用 IContainer 并不能告诉我们太多信息......因此您需要更仔细地查看以识别相互依赖关系。

The service location pattern is often considered an anti-pattern these days (using container.Resolve and injecting the container).

After MUCH struggling with this concept myself and trying to decide if I like it or hate it, I've come to the personal realization that I agree service location is an anti-pattern - because it obfuscates the interdependencies which exist and which are a core concept of OOP.

Have a read here:
http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx

I actually LIKE that fact that in option 1, Process CLEARLY expresses its dependency on each of the services it lists are parameters in the constructor. It makes the dependencies very obvious....and further I think it helps promote good design.

Just saying Processor takes an IContainer doesn't tell us very much...and thus you need to take a much closer look to identify interdependencies.

盛装女皇 2024-12-06 12:23:10

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

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

相反,您应该让容器自动装配 依赖项并解决它去

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

The answer given by JeffN825 is correct, but I'd like to add to it that you'd never create a new Processor instance using a container like this:

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

Rather, you'd let the container auto-wire the dependencies and resolve it one go:

Processor proc = container.Resolve<Processor>();
欢你一世 2024-12-06 12:23:10

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

This is not about number of dependencies, nor a per class decision. Approach 2 introduces a new dependency, but if you want to rely on an IoC container, than it is a good approach. Approach 3 is like the second, but let's you do some stuff in the Factory in future. Approach 1 is simplest, doesn't rely on anything and should be used for dependencies which you wouldn't usually manage through IoC container.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文