【问题标题】:Creating new instances while still using Dependency Injection在仍然使用依赖注入的同时创建新实例
【发布时间】:2011-10-18 10:03:13
【问题描述】:

环境简介:

我有一个代表聊天室并依赖于记录器的类。它与具有横切关注点的系统范围的记录器不同,而是与特定聊天室相关联的记录器。它将聊天室中的所有活动记录到其唯一的日志文件中。创建聊天室时我想打开日志文件,而当它被销毁时我想关闭日志文件。

问题

这是我正在使用的相关代码。

public interface IChatroomLogger
{
    void Log(ServerPacket packet);
    void Open();
    void Close();
}

public class ChatroomLogger : IChatroomLogger
{
    // chatroom name will be used as a file name
    public ChatroomLogger(string chatroomName) { ... }
    public void Log(ServerPacket packet) { ... }
}

public class Chatroom
{
    public Chatroom(string name, IChatroomLogger logger)
    {
        this.name = name;
        this.logger = logger;
        this.logger.Open();
    }

    public IChatromLogger Logger { get { return this.logger; } }
}

public interface IChatManager
{
    Chatroom Get(chatroomName);
}

它在应用程序中是这样使用的:

var room = ChatManager.Get(chatroomName);
romm.DoStuff();
room.Logger.LogPacket(receivedPacket);

ChatManager 是一个包含对所有聊天室的引用并负责创建和删除它们的类。我还没有写它,但这是我一直在编写的接口。

问题

如何让ChatManager 创建Chatroom 的新实例并仍然使用依赖注入??

我正在使用 Unity 完成所有其他 DI 工作。到目前为止,它工作得很好。但我不确定如何解决这个难题。

当我对ChatManager 的具体实现创建新聊天室时,它必须传入IChatroomLogger。它不知道如何构建它……但 Unity 知道。但随后我必须将IUnityContainer 传递到ChatManager

public class ChatManager : IChatManager
{
    public ChatManager(IUnityContainer container)
    {
        this.container = container;
    }

    public Chat Get(string chatroomName)
    {
        // get logger from Unity somehow. Not sure how I'd 
        // pass chatroomName to the concrete instance
        var logger = ...
        return new Chatroom(chatroomName, logger);
    }
}

出于某种原因,这似乎是错误的。让域对我正在使用的 DI 容器一无所知似乎更干净。

如果我的应用程序正在运行,我如何在不采用某种服务定位器设计的情况下获得 Chatroom 类的新实例?我是不是想多了?绕过Unity不是什么大不了的事吗?欢迎任何想法!

【问题讨论】:

标签: c# dependency-injection unity-container ioc-container


【解决方案1】:

你是对的。像这样使用 IUnityContainer 不再使用依赖注入。相反,它使用“服务定位器”模式。在这种情况下,我通常会创建一个IFactory<T> 接口,如下所示:

public IFactory<T>
{
    T Get();
}

然后用一个确实知道的类实现接口并使用IUnityContainer。设置您的绑定,以便IFactory&lt;&gt; 请求将创建此工厂类的实例。这样,您可以将IFactory&lt;Logger&gt; 接口注入您的ChatManager,并在您需要记录器实例的任何时候调用.Get()

【讨论】:

  • 好主意!我真的很喜欢它的简单性。不过有一个问题 - 我需要在我的具体记录器的构造函数中传递一个字符串(聊天室名称)。你能想出一个好方法吗?
  • @Onisemus:在这种情况下,您可能需要一个更专业的工厂接口 (ILoggerFactory),它将名称作为其 Get 方法的参数。工厂实现应该与您的 DI 绑定位于同一包中,并使用 Unity 提供的任何机制将该参数作为 DI 参数传递。
【解决方案2】:

一般来说,我也认为你应该避免传递容器。

  • 使用 Create(string roomname) 方法将 IChatroomProvider 添加到您的设计中
  • 在 ChatroomProvider 中,使用容器创建命名实例(容器将为您管理每个命名实例的生命周期,因此您无需管理字典)。
  • 向容器注册 ChatroomProvider
  • 让 ChatManager 依赖 IChatroomProvider
  • 当 ChatManager 需要聊天室时,只需询问其 IChatroomProvider
  • 使用容器创建 ChatManager 实例
  • 创建聊天室时将创建记录器实例

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-26
    • 1970-01-01
    • 1970-01-01
    • 2015-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多