Какой шаблон креативного дизайна подойдет этим требованиям? - PullRequest
4 голосов
/ 06 августа 2011

У меня есть сценарий, в котором я передаю объект «запрос» данных в службу, и сама служба должна создавать несколько различных «процессоров» в зависимости от данных в запросе.

Каждый процессор может быть одного из нескольких типов.Так, например, грубая уродливая реализация может выглядеть так:

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 ]

2 голосов
/ 06 августа 2011

Один шаблон, который приходит на ум, это Цепочка ответственности (возможно, не шаблон создания)

Во-первых, вам нужны 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 голос
/ 06 августа 2011

То, что вы хотите сделать, - это создать Фабрику, основной вопрос в том, как вы хотите ее настроить. Мне нравится следовать подходу, в котором выбор того, какой метод должен быть создан, входит в обязанности 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, если он имеет такую ​​функцию.

1 голос
/ 06 августа 2011

Фабрика, вероятно, верный путь, но вам нужно немного больше, а именно конфигурация.

Например, вам может потребоваться файл конфигурации, похожий на

<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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...