В шаблоне стратегии стратегия может принимать Контекст как параметр - PullRequest
10 голосов
/ 09 января 2010

Сводка обратной связи

Теперь я закрою эту теаду (я думаю, что больше не будет обратной связи) и попытаюсь обобщить то, что я понял

  1. использование «контекста» в качестве параметра для моей стратегии вводит тесную связь, которой следует избегать, а также может вынудить меня раскрыть свойства, которые, возможно, должны оставаться скрытыми в классе.
  2. Чтобы свести к минимуму связь, было бы лучше предоставить необходимые значения или, по крайней мере, использовать интерфейс вместо конкретного типа для стратегии.

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

Давайте возьмем следующую классическую реализацию

//The strategy
interface IStrategy  
{  
  void Execute();  
}  

class ConcreteStrategyA : IStrategy
{
  public void Execute()
  {
    Console.WriteLine( "Called ConcreteStrategyA.Execute()" );
  }
}

class ConcreteStrategyB : IStrategy
{
  public void Execute()
  {
    Console.WriteLine( "Called ConcreteStrategyB.Execute()" );
  }
}

//The context
class Context
{
  IStrategy strategy;

  // Constructor
  public Context(IStrategy strategy)
  {
    this.strategy = strategy;
  }

  public void UpdateContext(IStrategy strategy)
  {
    this.strategy = strategy;
  }

  public void Execute()
  {
    strategy.Execute();
  }
}

Все примеры, которые я видел, имеют довольно простые стратегии, которые принимают основные аргументы (например, целые числа). Я хотел бы знать, есть ли что-то не так, если стратегия использует контекст для выполнения работы.

Это даст что-то вроде

//The strategy
interface IStrategy  
{  
  void Execute(Context arg);  
}  

и вызов даст

//The context
class Context
{
  ....

  public void Execute()
  {
    strategy.Execute(this);
  }
}

Этого "сцепления" следует избегать? Это нормально?

Ответы [ 3 ]

7 голосов
/ 09 января 2010

Одна проблема, которую я вижу в вашем подходе, заключается в том, что между конкретным классом Context и экземплярами классов Strategy будет сильная связь. Это подразумевает, что классы Strategy могут использоваться только с классом Context. Один из способов обойти это состоит в том, чтобы сделать ваши классы стратегии зависимыми (или использовать) интерфейс, который реализует класс 'Context'.

EDIT Также, когда у классов Стратегии есть экземпляр класса Context, эти классы должны явно получать данные из класса Context. Это будет означать добавление геттеров (при необходимости) в класс Context для классов стратегии, чтобы получить необходимые данные. Но добавление геттеров не обязательно является хорошей практикой ОО, так как большее количество геттеров представляет риск нарушения инкапсуляции.

Альтернативой, которую вы можете придумать, является , а не передача ссылки (этого) класса Context на метод (ы) в классе стратегии, но передача только необходимых данных в класс Strategy.

Например, если класс Context выглядит примерно так: (код на Java)

</p> <pre><code>Context { IStrategy strategy; List<Integer> scores; public Context(IStrategy strategy) { this.strategy = strategy; scores = new ArrayList<Integer> } public print() { strategy.sort(scores); } } public interface IStrategy<Integer> { public void sort(List<Integer> l); }

В приведенном выше коде класс Strategy работает с общим списком Integer и не связан с классом Context. Кроме того, при определении класса Strategy можно использовать универсальный метод, чтобы метод sort применим не только к целым числам, но и к универсальным типам.

5 голосов
/ 09 января 2010

ИМХО, все в порядке. но я предпочитаю передавать контекст стратегии через конструктор класса реализации стратегии.

2 голосов
/ 10 января 2010

Ваш код - это ваш код, пишите все, что имеет для вас смысл. Тем не менее, у меня есть слово предостережения.

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

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

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

...