Замените переключатель Enum с шаблоном проектирования (IOC)

У меня есть обработчик событий, который получает объект eventargs внутри, который является перечисляемым значением, которое дополнительно уточняет информацию внутри. Это выглядит примерно так

public enum StatusCallbackType { Status1, Status2, Status3, Status4 }

public class StatusEventArgs
{
  public StatusCallbackType Type {get;set;}
  public StatusData Data {get; set;}
}

Statusdata - это базовый абстрактный класс, который изменяется в зависимости от заданного CalllbackType.

Теперь код, который обрабатывает событие, выглядит как

switch e.Type
{
  case Status1:
    DoAction1(e.Data as Opt1Data);
    break;
  case Status2:
    DoAction1(e.Data as Opt2Data);
    break;
  case Status3:
    DoAction1(e.Data as Opt3Data);
    break;
}

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

С другой стороны, мне это сейчас не нужно. Решения для коммутаторов работают, но они начинают набирать обороты, поэтому я борюсь между своим ощущением, что это не ремонт и YAGNI.

Есть ли шаблон, который позволяет конвертировать такие переключатели в шаблон IOC? Как вы думаете, мне стоит заняться рефакторингом этого переключателя?

3 ответа

Решение

Я думаю, что вы можете рефакторинг по схеме цепочки ответственности. Каждый оператор switch становится объектом-обработчиком в коллекции, которая либо обрабатывает уведомление, либо уведомление передается следующему.

Что касается внедрения, вы сможете изменять количество обработчиков без изменения клиентского кода и вставлять макеты / заглушки для тестирования.

Чтобы ответить, следует ли вам рефакторинг, нет ничего плохого в самом операторе switch, если он появляется только один раз и остается простым. Вы захотите провести рефакторинг, если начнете замечать дублирование или другие запахи кода, которые можно исправить с помощью шаблона.

Я хотел бы использовать что-то вроде шаблона Abstract Factory. Это очень полезно по отношению к IoC, потому что оно может инкапсулировать сложную логику, которая создает другие зависимости. Затем вы можете внедрить свою абстрактную фабрику с помощью инструмента IoC и избавиться от оператора switch.

Я бы использовал что-то вроде этого, возможно:

public interface IStatusHandler
{
    bool Handle(StatusData statusData);
}

public class Status1Handler : IStatusHandler
{
    public bool Handle(StatusData statusData)
    {
        if (statusData as Opt1Data == null) return false; // you don't need Type anymore

        ...

        return true;
    }
}

public class StatusManager
{
     private IList<IStatusHandler> handlers;

     public StatusManager(IList<IStatusHandler> handlers) // inject with IoC here
     {
         this.handlers = handlers;
     }

     public void ProcessStatus(StatusEventArgs args)
     {
         foreach(var handler in handlers)
             if (handler.Handle(args.Data)) return;

         throw new Exception("No handler for this kind of status!");
     }
}
Другие вопросы по тегам