【问题标题】:What are the basic principles of designing under Dependency Injection pattern依赖注入模式下设计的基本原则是什么
【发布时间】:2010-07-15 10:15:57
【问题描述】:

我对所有 DI 模式的想法是新手,我有一些基本的设计疑问。 我使用 Unity 应用程序块 2.0 作为我的 DI 框架。

问题:

  1. 假设我有一个名为 IDevice 的硬件设备接口。 以及一些接收此类 IDevice 的硬件侦听器。 现在假设您有多个实现 IDevice 和多个侦听器的硬件设备。 您需要为每个侦听器指定要注入的实际设备。 您不能只将单个设备映射到需要多个映射之类的接口。

一种可能的解决方案是为每个实际设备创建另一个抽象级别 喜欢

public interface IActualDevice : IDevice
{}

public ActualDevice : IActualDevice
{}

public SimulatedActualDevice : IActualDevice
{}

public OtherAcualDevice: IOtherAcualDevice
{}

那么就有可能创建这样的映射:

container.RegisterType<IActualDevice, ActualDevice>()

或者如果硬件丢失:

container.RegisterType<IActualDevice, SimulatedActualDevice>()

所以你说这个设计好不好?

  1. DI 模式为我们提供了良好的对象创建机制。

glue 呢,对象之间的事件订阅呢?

你不认为它丢失了,或者我错过了一些支持它的 Unity 功能更好。

阿迪尔。

【问题讨论】:

    标签: c# design-patterns dependency-injection unity-container


    【解决方案1】:

    无需引入标记接口来使您的 DI 容器工作 - 那将是一个泄漏抽象

    使用 Unity,您可以使用自己的 IDevice 实现配置每个 Listener,如下所示:

    container.RegisterType<IDevice, ActualDevice>("actual");
    container.RegisterType<IDevice, OtherActualDevice>("otherActual");
    
    container.RegisterType<IListener, Listener1>("listener1",
        new InjectionConstructor(
            new ResolvedParameter<IDevice>("actual")));
    container.RegisterType<IListener, Listener2>("listener2",
        new InjectionConstructor(
            new ResolvedParameter<IDevice>("otherActual")));
    

    您现在可以像这样解析监听器:

    var listener1 = container.Resolve<IListener>("listener1");
    var listener2 = container.Resolve<IListener>("listener2");
    

    一般来说,DI的核心模式是构造函数注入抽象工厂。大多数其他事情都来自这两个。更多 DI 模式和原则请参阅this answer

    【讨论】:

    • 正是我正在寻找的第一个问题的答案。我建议“泄漏抽象”,同时知道它的丑陋只是为了讨论以澄清我的观点。至于我的第二个问题,我想有一个 AppFactory 可以产生“胶水”——事件之间的所有事件订阅。你说什么?
    • 你可能想看看领域事件:msdn.microsoft.com/en-us/magazine/ee236415.aspx
    【解决方案2】:

    1) 这完全是个坏主意,因为接口旨在隐藏实现的细节。在任何地方使用 IDevice 类型并手动注入此依赖项

    IDevice d;
    
    if(a == 1)
    {
       d = container.Resolve<SimulatedActualDevice>()
    }
    else
    {
       d = container.Resolve<ActualDevice>()
    }
    
    User user = container.Resolve<IUser>();
    user.Device = d;
    

    如果您不想在代码中使用实现类名称,请使用命名注册:

    IDevice d;
    
    if(a == 1)
    {
       d = container.Resolve<IDevice>("Simulated")
    }
    else
    {
       d = container.Resolve<IDevice>("Actual")
    }
    
    User user = container.Resolve<IUser>();
    user.Device = d;
    

    2) 对象之间的事件订阅是对象初始化的一部分,而不是创建的一部分。 Unity 只是封装了“新”操作符。在构造函数或特殊工厂中进行订阅,就像在使用 DI 容器之前所做的那样。

    【讨论】:

    • -1 这个答案都推荐 Tight CouplingService Locator 反模式 - 这两个想法都非常糟糕。
    • 紧耦合仅用作示例,实际上这对于“策略”模式来说并不是一个坏主意。至于服务定位器 - 请提出另一种方式。最常见的例子——如何动态创建不同策略的对象?
    • 是的,你将如何实现这样的抽象工厂?像stackoverflow.com/questions/1926826/cant-combine-factory-di/… 那样手动创建对象?在那种情况下,你的抽象工厂将有一堆不必要的依赖。在实现该工厂时使用 Tight Coupling 和服务定位器要好得多。
    • 查看我对该问题的评论。
    猜你喜欢
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-29
    • 1970-01-01
    • 2021-04-09
    • 2015-10-19
    • 1970-01-01
    相关资源
    最近更新 更多