什么样的创作设计模式适合这些要求?

时间:2011-08-06 10:11:51

标签: c# java design-patterns

我有一个场景,我将数据'request'对象传递给服务,并且服务本身必须根据请求中的数据创建许多不同的'处理器'。

每个处理器本身可以是多种不同类型中的一种。例如,粗略的丑陋实现可能看起来像:

public Collection<IProcessor> UglyCreationalMethod(Request request)
{
    var processors = new Collection<IProcessor>();

    if(request.Type == RequestType.SomeVal)
    {
        if(request.Id > 1000)
        {
            processors.Add(new ProcessLargeRequest(request));
        }
        else
        {
            processors.Add(new ProcessSmallRequest(request));
        }
    }
    else (request.Type == RequestType.SomeOtherVal)
    {
        if(request.Source == RequestSource.User)
        {
            processors.Add(new ProcessUserRequest(request));
        }
        else
        {
            processors.Add(new ProcessCorpRequest(request));
        }
    }

    if(request.SomeProp == "blah")
        processors.Add(new ProcessBlahRequest(request));

    // ... etc ad infinitum :)

    return processors;
}

我正在寻找一种可扩展的模式,并隐藏了决定服务需要创建的处理器类型的讨厌逻辑,因此它比上面的丑陋代码更清晰,更易于维护。

我了解工厂方法,但仅靠这些方法是不够的。

建议表示赞赏。

3 个答案:

答案 0 :(得分:2)

一种想到的模式是责任链(可能不是创作模式)

首先,您需要RequestHandlers

public interface IRequestHandler
    {
        bool CanHandle(Request req);

        void Handle(Request req);
    }

    public class LargeRequestHandler : IRequestHandler
    {
        public bool CanHandle(Request req)
        {
            return (req.Type == RequestType.SomeVal && req.id > 1000);
        }

        public void Handle(Request req)
        {
            processors.Add(new ProcessLargeRequest(request));
        }
    }

    public class SmallRequestHandler : IRequestHandler
    {
        public bool CanHandle(Request req)
        {
            return (req.Type == RequestType.SomeVal && req.id < 1000);
        }

        public void Handle(Request req)
        {
            processors.Add(new SmallLargeRequest(request));
        }
    }

...同样可以根据需要为更多处理程序添加类。

然后创建这些处理程序的链,如

public class RequestChain
    {
        IRequestHandler[] handlers;

        public RequestChain()
        {
            handlers = new[] { new LargeRequestHandler(), new SmallRequestHandler() };
        }

        public void ProcessRequest(Request req)
        {
            foreach (var handler in handlers)
            {
                if (handler.CanHandle(req))
                {
                    handler.Handle(req);
                }
            }
        }
    }

希望这会有所帮助。欢呼声。

答案 1 :(得分:1)

工厂可能是正确的方法,但你需要更多的东西,即配置。

例如,您可能需要一个类似于

的配置文件
<processor type="typename">
  <rules>
    <rule type="requestIdThresholdRule">
      <configuration evaluationType="ExceedsThreshold" threshold="1000"/>
    </rule>
  </rules>
</processor>
<processor type="othertypename">
  <rules>
    <rule type="yadda">
       <configuration evaluationType="DoesNotMeetThreshold" threshold="1000"/>
    </rule>
  </rules>

这使您可以灵活地定义基于上下文的运行时评估创建哪些类型。您没有一大堆代码存在于工厂方法本身,而是在一些主要由配置值驱动的规则中。代码少得多,灵活得多。

然后你就这样称呼它:

 List<ISomething> items = ISomethingFactory.CreateISomethingsForContext(context);

答案 2 :(得分:1)

您要做的是创建工厂,主要问题是您希望如何配置它。我喜欢遵循一种方法,选择应该创建哪种方法属于Factory的职责而不是正在创建的类 - 这会带来更好的可配置性,并且更易于管理。

我会创建这样的东西:

    public struct ProcessorCreationSettings
    {
        public Predicate<Request> Predicate;
        public Func<Request, IProcessor> Creator;
    }

    public class ProcessorFactory
    {
        protected static List<ProcessorCreationSettings> settings = new List<ProcessorCreationSettings>();

        static ProcessorFactory()
        {
            settings.Add(new ProcessorCreationSettings
            {
                Predicate = r => r.Type == RequestType.SomeOther && r.Id > 1000,
                Creator = r => new ProcessLargeRequest(r)
            });
            settings.Add(new ProcessorCreationSettings
            {
                Predicate = r => r.Type == RequestType.SomeOther && r.Id <= 1000,
                Creator = r => new ProcessSmallRequest(r)
            });
        }

        public List<IProcessor> Create(Request request)
        {
            return settings
                .Where(s => s.Predicate(request))
                .Select(s => s.Creator(request))
                .ToList();
        }
    }

配置部分由静态列表完成,但如果它具有此功能,您也可以使用IoC容器。