Стратегия Pattern правильная вещь? - PullRequest
3 голосов
/ 30 ноября 2010

Я надеюсь, что вы можете помочь мне с моей проблемой:

У меня есть класс, который делает мыльные звонки. Но если определение мыла изменится, мне придется написать новый класс или унаследовать его и т. Д. Поэтому я пришел к решению написать что-то вроде этого:

switch(version)
{
  case "1.0":
     saopV1.getData()
  case "2.0":
     soapV2.getData()
}

Ну, довольно плохой код, я знаю. Затем я прочитал о паттерне «Стратегия» и подумал: «Вау, это то, что мне нужно, чтобы избавиться от этой плохой вещицы с переключателями»:

abstract SoapVersion
{
    public SoapVersion GetSoapVersion(string version)
    {
         //Damn switch-case thing
         //with return new SoapV1() and return new SoapV2()
    }
    public string[] virtual getData()
    {
          //Basic Implementation
    }
}

class SoapV1:SoapVersion
{
       public override string[] getData()
       {
           //Detail Implementation
       }
}

class SoapV2:SoapVersion
{//the same like soapv1}

Но я не могу избежать использования "ifs" или переключать регистры в моем коде. Возможно ли это с помощью ОО-технологий ??

Edit: Функция GetSoapVersion должна быть статической

Ответы [ 6 ]

4 голосов
/ 30 ноября 2010

Это более или менее правильный способ сделать это красивым способом. В какой-то момент в вашем коде вам придется принять решение, использовать ли v1 или v2, так что вам все равно придется иметь условное выражение (если или переключаться). Однако, используя стратегию и фабрику (фабричный метод или фабричный класс), вы централизуете это решение.

Я бы сделал метод фабрики в абстрактном классе статичным. Кроме того, я хотел бы использовать шаблон шаблонного метода: то есть открытый, не переопределяемый метод GetData, который вызывает защищенный виртуальный (абстрактный) метод, который должен быть переопределен в конкретной реализации.

public abstract class SoapProcessor
{

    protected SoapProcessor() { /* protected constructor since public is of no use */  }

    public static SoapProcessor Create( SoapVersion version )
    {
          switch( version )
          {
               case SoapVersion.Version1 : return new SoapV1Processor();
               case SoapVersion.Version2 : return new SoapV2Processor();
               default: throw new NOtSupportedException();
          }
    }


    public string[] GetData()
    {
         return GetDataCore();
    }

    protected abstract GetDataCore();
 }

}

1 голос
/ 30 ноября 2010

Вы не нуждаетесь в переключателях или операторах if.
Просто используйте делегирование .
То есть конкретные реализации абстрактного класса будут работать по мере необходимости (т.е. SoapV1, SoapV2 и т. д.), и клиент устанавливает соответствующий экземпляр в ссылке на объект .
У вас есть только ссылка на базовый класс, и соответствующий подкласс устанавливается клиентом. Ваш код просто вызывает методы базового класса (который во время выполнения является одной из производных реализаций). Например. пример ( ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ : не скомпилированный код. Только образец)

public abstract class SoapHandler
{

    protected abstract string[] getData();
 }

public class SoapHandlerV1 extends SoapHandler
{

    public string[] getData(){
        //V1 implementation
    }

}
public class SoapHandlerV2 extends SoapHandler
{

    public string[] getData(){
        //V2 implementation
    }

}


public class SoapProcessor{

    public SoapHandler soapHandler;

    public setSoapHandler(SoapHandler h)
    {
                soapHandler = h;
    }

    public String[] getData(){
        //delegate to specific version
        soapHandler->getData();
    }
}


//in your code
SoapProcessor soap = new SoapProcessor();
soap.setSoapHandler(new SoapHandlerV1());
String[] soapData = soap.getData();//Will get the appropriate version
//use soap data
//do stuff

Посмотрите на примере GoF для стратегии, чтобы понять, что я имею в виду, если неясно

1 голос
/ 30 ноября 2010

В аналогичных обстоятельствах я выбираю между отражением и if/case с использованием следующего критерия: если поддержка новой версии должна быть добавлена ​​динамически (например, плагины), я выбираю отражение, иначе - if/case.Как уже упоминалось в других ответах, он должен внутри фабричного метода обеспечить единое место для создания вещей.Стоит отметить, что Strategy является поведенческим паттерном, а то, что вы просили, выглядит креативным.

1 голос
/ 30 ноября 2010

Это разница, если у вас есть коммутаторы только на фабриках или во всем коде. У вас есть решение (какую реализацию выбрать) по одному пункту.

0 голосов
/ 30 ноября 2010

Вы должны запрограммировать интерфейс, не являющийся реализацией .

Иметь отдельный сервисный интерфейс, который вы можете использовать со стороны клиента.

public interface IService
{
    string[] GetData();
}

и код вашего клиента как -

IService srvice = ServiceFactory.GetProxy();
string[] value = service.GetData();

Таким образом, код вашего клиента не изменится при изменении прокси службы.

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

  1. Считывание класса реализации и имени сборки из файла конфигурации и его создание с использованием отражения.
  2. Создание словаряэкземпляров прокси с мыльной версией в качестве ключей.
0 голосов
/ 30 ноября 2010

Поскольку version известен только во время выполнения, он определенно будет сводиться к некоторому условию (если или переключаться, или использовать карту между строками и прототипом и т. Д.).

Следовательно, достойная цель - сократить количество условных выражений / изолировать точки изменения.

...