Порекомендуйте шаблон дизайна - PullRequest
8 голосов
/ 08 августа 2011

Приложение, над которым я работаю, рабочие процессы.В зависимости от состояния рабочего элемента доступно несколько действий."Завершить", "Отменить", "Переназначить" и т. Д. *

Для обеспечения функциональности для действий, в настоящее время у меня есть интерфейс, который выглядит примерно так ...

public interface IActionProvider{
    public void Complete(WorkItem workItem);
    public void Cancel (WorkItem workItem);
    public void Reassign(WorkItem workItem);
}

Затем на основена других деталях рабочего элемента у меня есть конкретные реализации интерфейса.Например, ...

public class NormalActionProvider :IActionProvider
{
    ...
}

и

public class UrgentActionProvider : IActionProvider
{
   ....
}

Проблема в том, что если я хочу добавить новое действие, скажем ... "Делегат", я должен обновитьинтерфейс, который, конечно, оказывает влияние на все реализации.

Это нарушает принцип открытия / закрытия?Можете ли вы порекомендовать шаблон дизайна или рефакторинг, который может помочь мне здесь?

Ответы [ 5 ]

11 голосов
/ 08 августа 2011

Похоже, что шаблон команды подойдет.Вы можете изменить / добавить больше команд.Командные классы отделены от основной программы.

public interface IActionProvider{
    public void execute(WorkItem item,ActionType actionType);
}

ActionType представляет Завершено, Отмена и так далее.Вы можете добавлять новые типы действий и подключать соответствующие классы команд.

3 голосов
/ 08 августа 2011

Вы всегда можете добавить Decorator в интерфейс IActionProvider (следуйте шаблону Designrator ).

0 голосов
/ 08 августа 2011

Я бы также выбрал шаблон команды. В качестве усовершенствования вы можете объединить его с методом абстрактной фабрики, чтобы у вас был класс фабрики для каждого класса команд, и все эти фабрики реализуют общий интерфейс фабрики.

Например:

// C#
public interface ICommand { void Execute(); }

public interface ICommandFactory { ICommand Create(); }

public class CommandFactoryManager
{
    private IDictionary<string, ICommandFactory> factories;

    public CommandFactoryManager()
    {
        factories = new Dictionary<string, ICommandFactory>();
    }

    public void RegisterCommandFactory(string name, ICommandFactory factory)
    {
        factories[name] = factory;
    }

    // ...
}

Таким образом, вы можете динамически регистрировать новые фабрики команд. Например, вы можете загрузить DLL во время выполнения и извлечь все классы, которые реализуют интерфейс ICommandFactory, используя отражение, и у вас есть простая система плагинов.

0 голосов
/ 08 августа 2011

«В зависимости от состояния рабочего элемента», приводит Государственный шаблон проектирования

Так или иначе, вам придется реорганизовать интерфейс и в конечном итоге разорвать клиентские контракты.

Если я правильно понял вашу проблему, значит, у вас есть WorkItemProcessor, состояние которого изменяется на WorkItem, отправленных ему.

Поэтому ваш WorkItemProcessor становится

// Context
    public class WorkItemProcessor
    {
        public IState CurrentState { get; set; }

        public WorkItemProcessor(IState initialState)
        {
            CurrentState = initialState;
        }

        public void Process(WorkItem workItem)
        {
            CurrentState.Handle(this, workItem);
        }
    }

Затем мы определяем несколько состояний, которые WorkItemProcessor потенциально может находиться в

// State Contract
    public interface IState
    {
        void Handle(WorkItemProcessor processor, WorkItem item);
    }

    // State One
    public class CompleteState : IState
    {
        public void Handle(WorkItemProcessor processor, WorkItem item)
        {
            processor.CurrentState = item.CompletenessConditionHoldsTrue ? (IState) this : new CancelState();
        }
    }

    // State Two
    public class CancelState : IState
    {
        public void Handle(WorkItemProcessor processor, WorkItem item)
        {
            processor.CurrentState = item.CancelConditionHoldsTrue ? (IState) this : new CompleteState();
        }
    }

Предположим, ваш WorkItem выглядит как

 // Request
    public class WorkItem
    {
         public bool CompletenessConditionHoldsTrue { get; set; }

         public bool CancelConditionHoldsTrue { get; set; }
    }

Чтобы сложить все вместе

static void Main()
    {
      // Setup context in a state 
      WorkItemProcessor processor = new WorkItemProcessor(new CancelState());

      var workItem1 = new WorkItem {  CompletenessConditionHoldsTrue = true };
      var workItem2 = new WorkItem {  CancelConditionHoldsTrue = true };

      // Issue requests, which toggles state 
      processor.Process(workItem1);
      processor.Process(workItem2);

      Console.Read();
    }

Надеюсь, это приблизит вас. Приветствия.

0 голосов
/ 08 августа 2011

Это зависит от того, чего вы действительно пытаетесь достичь с помощью IActionProvider. Если вы действительно хотите сделать так, чтобы каждая реализация могла выполнять все действия, которые вы считаете важными, то это должно быть частью интерфейса, который они реализуют. Интерфейсы работают лучше, если они хорошо спланированы заранее, поэтому им не нужно постоянно менять.

Но, похоже, вы не обязательно хотите, чтобы все действия выполнялись всеми провайдерами. Мне нужно было бы знать больше деталей, чтобы дать хороший совет, но одним примером может быть то, что провайдеры инициализируют себя по отношению к некоему шине событий. Они могут подписаться на те события, которые им небезразличны, и выполнять действия только для событий, которые имеют смысл для конкретной реализации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...