首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >打造更好的工厂

打造更好的工厂
EN

Stack Overflow用户
提问于 2012-10-12 01:16:13
回答 4查看 480关注 0票数 3

所以我正在做一个项目,我从数据库中获取一些数据--有两块数据使这个项目变得很好,一块我有类型(他们称之为事件,但它本质上只是转换成我创建的.NET类型),然后我有XML,我设计了对象,这样它们就可以很好地反序列化了。所有这些都很棒,经过了单元测试,所有的类和方法都遵循单一责任原则。

当我创建工厂来构建业务逻辑来处理我从XML创建的.NET对象时,我的体系结构技能变得模糊了。

基本上这就是我所拥有的。

代码语言:javascript
复制
  public class EventProcessorFactory : IEventProcessorFactory
    {
        private readonly List<IEventProcessor> _eventProcessors;

        public EventProcessorFactory()
        {
            _eventProcessors = new List<IEventProcessor>();
        }

        public IEventProcessor GetProcessor(Type eventType)
        {
            var typeOfEventProcessor = GetProcessorFromEventType(eventType);
            if (_eventProcessors.Any(x => x.GetType() == typeOfEventProcessor))
                return _eventProcessors.Single(x => x.GetType() == typeOfEventProcessor);
            var processor = BuildProcessorFromType(typeOfEventProcessor);
            _eventProcessors.Add(processor);
            return processor;
        }

        private static Type GetProcessorFromEventType(Type eventType)
        {
            if (eventType == typeof(EnrollmentEventType))
                return typeof(EnrollmentEventProcessor);
            if (eventType == typeof(ClaimantAccountInfoEventType))
                return typeof(ClaimantAccountInfoEventProcessor);
            if (eventType == typeof(PhoneUpdateEventType))
                return typeof(PhoneUpdateEventProcessor);
            if (eventType == typeof(AddressUpdateEventType))
                return typeof(AddressUpdateEventProcessor);
            if (eventType == typeof(ClientAccountInfoEventType))
                return typeof(ClientAccountInfoEventProcessor);
            return null;
        }

        private IEventProcessor BuildProcessorFromType(Type typeOfEventProcessor)
        {
            return ((IEventProcessor)Activator.CreateInstance(typeOfEventProcessor));
        }
    }

所以这是可行的,但它看起来相当笨拙。我读过一些关于使用工厂的文章,但是我要么没读对,要么就是没读懂。我对上面的代码有两个问题。

1)如果你添加了一个新的事件,你需要去修改它,我希望以后的开发人员能够只删除"MyCoolNewEventType“和"MyCoolNewEventProcessor”,而不必修改匹配事件到处理器的方法。

2)现在,当我创建一个实例时,我可以只调用.CreateInstance();这很好,因为我没有任何依赖关系,但“事件处理器”可能至少在数据库上有依赖关系。我不是100%确定如何处理它,我不想随机调用Container.Resolve()。

如果有人能指出正确的方向,那将是巨大的。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-10-12 10:11:21

这在某种程度上取决于您希望存储映射的位置,但您可以编写一个自定义配置节:

代码语言:javascript
复制
public class EventProcessorMapping : ConfigurationElement
{

    [ConfigurationProperty("event", IsRequired = true)]
    public string Event
    {
        get
        {
            return this["event"] as string;
        }
    }

    [ConfigurationProperty("processor", IsRequired = true)]
    public string Processor
    {
        get
        {
            return this["processor"] as string;
        }
    }
}

[ConfigurationCollection(typeof(EventProcessorMapping), CollectionType = ConfigurationElementCollectionType.AddRemoveClearMap)]
public class EventProcessors : ConfigurationElementCollection
{
    public EventProcessorMapping this[int index]
    {
        get
        {
            return BaseGet(index) as EventProcessorMapping;
        }
        set
        {
            if (BaseGet(index) != null)
            {
                BaseRemoveAt(index);
            }
            BaseAdd(index, value);
        }
    }

    protected override ConfigurationElement CreateNewElement()
    {
        return new EventProcessorMapping();
    }

    protected override object GetElementKey(ConfigurationElement element)
    {
        return ((EventProcessorMapping)element).Event;
    }
}

public class RegisterEventProcessorsConfig : ConfigurationSection
{

    public static RegisterEventProcessorsConfig GetConfig()
    {
        return (RegisterEventProcessorsConfig)ConfigurationManager.GetSection("RegisterEventProcessors") ?? new RegisterEventProcessorsConfig();
    }

    [ConfigurationProperty("EventProcessors")]
    public EventProcessors EventProcessors
    {
        get
        {
            var o = this["EventProcessors"];
            return o as EventProcessors;
        }
    }

}

然后在你的App.config中,你可以拥有:

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="RegisterEventProcessors" type="UnitTestProject1.RegisterEventProcessorsConfig, UnitTestProject1"></section>
  </configSections>

  <RegisterEventProcessors>
    <EventProcessors>
      <add event="UnitTestProject1.ClaimantAccountInfoEventType, UnitTestProject1" processor="UnitTestProject1.ClaimantAccountInfoEventProcessor, UnitTestProject1" />
      <add event="UnitTestProject1.EnrollmentEventType, UnitTestProject1" processor="UnitTestProject1.EnrollmentEventProcessor, UnitTestProject1" />
    </EventProcessors>
  </RegisterEventProcessors>
</configuration>

因此,这至少重新定位了映射配置。至于工厂,如果你不介意处理器类在工厂创建时被实例化,你可以这样做:

代码语言:javascript
复制
public class EventProcessorFactory : IEventProcessorFactory
{
    private readonly Dictionary<Type, IEventProcessor> _eventProcessors;

    public EventProcessorFactory(IEnumerable<EventProcessorMapping> eventProcessorMappings)
    {
        _eventProcessors = new Dictionary<Type, IEventProcessor>();
        foreach (var mapping in eventProcessorMappings)
        {
            AddMapping(Type.GetType(mapping.Event), Type.GetType(mapping.Processor));
        }
    }

    public IEventProcessor GetProcessor<T>() where T : IEventType
    {
        return _eventProcessors[typeof(T)];
    }

    private void AddMapping(Type eventType, Type processorType)
    {
        var processor = (IEventProcessor)Activator.CreateInstance(processorType);
        _eventProcessors[eventType] = processor;
    }
}

在构造函数中,我们传入一个映射配置元素的集合,然后立即创建处理器并将其存储在私有集合中。然后,从工厂获取处理器基本上只是一个字典查找。

这两个部分如下所示:

代码语言:javascript
复制
[TestMethod]
public void TestFactory()
{
    var config = RegisterEventProcessorsConfig.GetConfig();
    var factory = new EventProcessorFactory(config.EventProcessors.Cast<EventProcessorMapping>());

    var processor = factory.GetProcessor<EnrollmentEventType>();
    Assert.IsInstanceOfType(processor, typeof(EnrollmentEventProcessor));
}
票数 1
EN

Stack Overflow用户

发布于 2012-10-12 01:22:02

你要找的是可配置的工厂。它可以使用依赖注入框架来完成,或者是最简单的方式--外部配置(想到xml文件),它将存储您可能实现的列表,并将根据需要进行加载/修改。

使用此解决方案,您将拥有以下内容

代码语言:javascript
复制
<Processors>
  <Processor dllname='' classname=''>
   ....
</Processors>

您必须使用反射/ .net提供的任何xml读取技术来加载它。

票数 4
EN

Stack Overflow用户

发布于 2012-10-12 01:35:49

您可以使用reflection并在这些属性中设置处理器类型。

代码语言:javascript
复制
[ProcessorType(typeof(EnrollmentEventProcessor)]
class EnrollmentEvent { ... }

简单而干净的解决方案。对于创建的类型,我建议使用Dictionary<Type, Object>来加快访问速度。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12845005

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档