Каков шаблон стратегии с обратным потоком контроля? - PullRequest
1 голос
/ 06 февраля 2012

В моем понимании шаблон стратегии используется для того, чтобы сделать поведение взаимозаменяемым.Это предполагает, что ответственность за стратегию определяется в интерфейсе, которому клиент может затем делегировать вызовы.Например, предположим, что значение может быть получено различными способами, интерфейс будет иметь метод "getValue ()".

Мой вопрос касается случая, когда поток управления противоположен.Например, если конкретная стратегия инициирует запрос "onValueChanged ()" на клиенте (предположим, что он имеет ссылку на клиент или интерфейс обратного вызова).

Это все еще считается шаблоном стратегии?

Обновление - добавлен следующий пример исходного кода:

interface DataSupplierCb
{
  void onValueChanged(int a);
}

interface DataSupplier
{
  void check();
}

// NOTE 1: Data supplier knows how the get the value
class ConcreteDataSupplier : public DataSupplier
{
  void check()
  {        
    myDataSupplierCb.onValueChanged(47);
  }
}

class Client : public DataSupplierCb
{
  void onValueChanged(int a)
  {
    // NOTE 2: Client knows what to do with the value
  }

  void changeDataSupplier(int i)
  {
    if (i == 1)
    {
      myCurrentDataSupplier = new ConcreteDataSupplier(this);
    }
  }
}

Ответы [ 2 ]

2 голосов
/ 07 февраля 2012

Нет. Это не будет паттерном стратегии. В шаблоне стратегии интерфейс стратегии и конкретные реализации стратегии не знают о клиенте.

Клиент знает об интерфейсе стратегии и ничего не знает о реальных реализациях.

Целью этого паттерна является возможность замены одной стратегии другой без изменения клиента. Стратегия - это обычно какой-то алгоритм.

То, что вы описываете, похоже, ближе к шаблону проектирования Observer, в котором есть субъект и один или несколько наблюдателей, реализующих общий интерфейс (или наследующих от общего базового класса). Субъект - это объект, за которым наблюдают, а наблюдатели - это объекты, о которых нужно уведомлять всякий раз, когда объект изменяется. Например: субъект может быть источником данных, один наблюдатель может быть видом гистограммы, а другой - круговой диаграммой.

http://en.wikipedia.org/wiki/Observer_pattern
http://en.wikipedia.org/wiki/Strategy_pattern
1 голос
/ 08 февраля 2012

Если намерение интерфейса DataSupplier, чтобы позволить вашему Client обмениваться и делегировать различные конкретные реализации извлечения данных, тогда да, это можно считать стратегией.Ваш Client защищен от подробностей (иначе говоря, стратегии), используемых для получения значения, как ожидается при использовании шаблона Стратегия.И тот факт, что ссылка Client передается в Стратегию, является нормальным и распространенным явлением:

(From the GoF)

"Стратегия и Контекст взаимодействуют для реализации выбранного алгоритма.Контекст может передавать все данные, требуемые алгоритмом, в стратегию при вызове алгоритма. В качестве альтернативы, контекст может передавать себя в качестве аргумента операциям Стратегии. Это позволяет стратегии отозвать контекст в случае необходимости . "

Контекст для вас: Client.

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

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

abstract class DataSupplier
{

   protected ClientInterface _client;

   // ctor takes in context
   public DataSupplier(ClientInterface client)
   {
      _client - client;
   }

   public void check()
   {
      int priorValue = 46;

      int newValue = OnGetValue(); 

      if (priorValue != newValue)
         _client.onValueChanged(newValue)

   }

   protected abstract int OnCheck();

}

А затем:

class ConcreteDataSupplier : DataSupplier
{

   // Check, and notification, are handled by the base.  We only need
   // to implement the actually data fetching

   int OnGetValue()
   {        
      return someValue;
   }
}

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

...