【问题标题】:Handlers factory with dependency injection design具有依赖注入设计的处理程序工厂
【发布时间】:2012-03-07 22:00:08
【问题描述】:

我的项目已经包含一些处理程序的工厂(代码非常简化):

class HandlersFactory
{
    private static readonly Dictionary<string, IHandler> registeredHandlers =
        new Dictionary<string, IHandler>
        {
            { "First", new FirstHandler() },
            { "Second", new SecondHandler() },
            { "Third", new ThirdHandler() },
        };

    public bool IsRegisteredHandler(string name)
    {
        return registeredHandlers.ContainsKey(name);
    }

    public IHandler GetHandler(string name)
    {
        if (!IsRegisteredHandler(name))
            return null;

        return registeredHandlers[name];
    }
}

处理程序列表是硬编码的。工厂位于主程序集中,但应用程序可以在运行时使用附加程序集进行扩展(主应用程序搜索它们并在启动时加载)。附加组件自定义应用程序。

必须有可能用新的“替换”主程序集中的一些处理程序(提供另一种逻辑)。因此,例如,加载附加程序集时,工厂将按名称“Second”返回CustomSecondHandler,而不是SecondHandler。我可以重写工厂,但更改不得影响已经使用它的代码。

我考虑过将字典初始化移动到某个方法RegisterHandlers,该方法可以在自定义工厂中被覆盖。并添加工厂的依赖注入,因此额外的程序集提供了从现有工厂派生的自己的工厂实现。如果未加载其他程序集,则使用默认工厂。但我觉得这种方法有问题。

请提出您的想法。我需要一个干净的解决方案,代码编写最少,以提供将替换现有处理程序的自定义处理程序。

谢谢。

【问题讨论】:

    标签: c# design-patterns dependency-injection factory-pattern


    【解决方案1】:

    您如何扫描这些处理程序的程序集?如果你使用反射,你可以使用custom attributes。考虑:

    [ForcesHandlerRegistrationOverride]
    public class CustomSecondHandler : IHandler
    {
        // ...
    }
    

    我假设您有办法为加载的处理程序生成正确的字典键并创建处理程序实例 - 跳过这些部分(namehandler 变量初始化),程序集扫描可能如下所示:

    var types = loadedAssembly
        .GetTypes()
        .Where(t => type.IsAssignableFrom(typeof(IHandler)));
    
    foreach (var type in types)
    {
        if (factory.IsRegisteredHandler(name))
        {
            // usually you'll do nothing here, but now we check if handler
            // we want to register is marked with custom attribute so that
            // we can override already registered handler
            var canForceOverride = type.GetCustomAttributes(
                typeof(ForcesHandlerRegistrationOverride), true).Length > 0;
            if (canForceOverride)
            {
                factory.RegisterHandler(name, handler);
                // ...or to keep this one safe, add more appropriate method
                // for explicit replacement (see note below)
            }      
        }
        else
        {
            factory.RegisterHandler(name, handler);
        }
    }
    

    如果您在工厂类上的注册方法以某种方式防止将处理程序添加到已经存在的密钥两次,您可能必须摆脱它(或公开可以替换处理程序的注册方法;比如ReplaceHandlerForceRegistration)。

    这将让您轻松控制您的类型何时应该覆盖/替换现有处理程序,或者只是注册为新的处理程序。

    请注意,您可以更进一步;使用应该替换的处理程序名称声明您的属性 - [ForcesHandlerRegistrationOverride("Second")]

    【讨论】:

    • 一个绝妙的主意!和一个非常干净的解决方案。我可能会从字典中删除readonly 并添加用于扫描自定义处理程序的附加程序集的方法。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    相关资源
    最近更新 更多