Есть ли у этого варианта паттерна стратегии название? - PullRequest
1 голос
/ 02 апреля 2009

У меня есть стандартный шаблон стратегии GOF: клиентский код содержит ссылку на AbstractStrategy, которая указывает на любую из нескольких ConcreteStrategies, производных от AbstractStrategy или реализации.

Одна ConcreteStrategy делегирует любую из нескольких других ConcreteStrategies, в зависимости от переданных ей параметров, например ::

public class ConcreteStrategy0 {
public void doStrategy(SomeType someData) {
   switch( somefunc(someData ) {
    case 0: ConcreteStrategy1.singleton.doStrategy(someData); break; 
    case 1: ConcreteStrategy2.singleton.doStrategy(someData); break;
    default: ConcreteStrategy3.singleton.doStrategy(someData); break;
   }
}

Это не совсем Коплиен Конверт / Письмо (поскольку намерение не совсем то же самое).

Но у него есть имя?

Ответы [ 3 ]

3 голосов
/ 03 апреля 2009

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

Указанный выше код нарушает Открытый / Закрытый принцип , и мне интересно, может ли он быть назван или имеет имя для выше code.


После мыслей : Когда вы звоните ConcreteStrategy0.doStrategy, вы в основном звоните как

new ConcreteStrategy0().doStrategy(someData);

Хотя это могло бы быть лучше рефакторинг как

// Inject strategy: Delegate object creation to a factory
new ConcreteStrategy0().doStrategy(StrategyFactory.Create(), someData);

// And update "doStrategy" to,
public void doStrategy(IStrategy strategy, SomeType someData)
{
    strategy.singleton.doStrategy(someData);
}

Или полностью передать ответ на стратегию,

// OR Let the strategy do stuff instead
StrategyFactory.Create().doStrategy(someData);
0 голосов
/ 08 апреля 2009

Для меня это выглядит как диспетчер: он принимает запрос и принимает решение на основе некоторых параметров, на какой обработчик его перенаправить.

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

<bean id="client" class="...">
  <property name="strategy" ref="dispatcherStartegy"/>
</bean>
<bean id="dispatcherStartegy" class="...">
  <property name="strategies">
    <map>
      <entry key="0" ref="concreteStrategy1"/>
      <entry key="1" ref="concreteStrategy2"/>
    </map>
  </property>
  <property name="fallbackStrategy" ref="concreteStrategy3"/>
</bean>
<bean id="concreteStrategy1" ... />
<bean id="concreteStrategy2" ... />
<bean id="concreteStrategy3" ... />

А занятия будут следующими:

class Client {
  Strategy strategy;
  public void setStrategey(Strategy strategy {... }
  public void doSomething(...) {
    ...
    strategy.doStrategy(...);
    ...
  }
}

class DispatcherStrategy implements Strategy {
  Map<Integer,Strategy> strategies;
  Strategy fallbackStrategy;
  ... getters, setters ...
  public void doStrategy(...) {
    Strategy s  = strategies.get(keyFromArguments);
    if ( s==null ) {
      s = fallbackStrategy
    }
    s.doStrategy(...)
  }
}

И, таким образом, любое изменение стратегии просто изменит конфигурацию приложения, а не код.

0 голосов
/ 02 апреля 2009

Похоже на сочетание стратегии и фабричного метода паттерна. Я сомневаюсь, что у этого есть имя само по себе. Но зачем вам действительно нужен оператор switch? Я думаю, что Абстрактный Фабричный образец был бы здесь лучше.

...