19
December

Паттерн Strategy (Стратегия)

Posted in: Паттерны проектирования |

Этот паттерн проектирования известен также под названием Policy. Суть его состоит в том, чтобы создать несколько моделей поведения (стратегий) для одного объекта и вынести их в отдельные классы. Вот ряд преимуществ данного паттерна:

  • позволяет выбирать модель поведения объекта динамически;
  • упрощает процесс добавления новых стратегий;
  • является альтернативой наследованию;
  • избавляет от множества условий (if, case);
  • делает еще много всего.

Если вам понятно, что значит каждый из этих пунктов (особенно 5-ый), переходите сразу к примеру на Java. А мы пока рассмотрим эти пункты немного подробнее.

Инкапсулирование стратегии в отдельном классе позволяет менять поведение объекта динамически. Очевидно, что для добавления новой стратегии нужно создать независимый класс и реализовать необходимые функции. Аналогично, для изменения или удаления стратегии опять же будет затронут только один класс.
Для выбора модели поведения часто используют наследование. Имея некоторый объект, мы создаем новый экземпляр подкласса этого объекта и присваиваем его самому объекту. При использовании паттерна Startegy, достаточно переключится на интересующую нас стратегию.
Если поведение объекта описывается несколькими методами, паттерн Strategy уменьшит кол-во условий в коде программы. Условный оператор понадобится нам не более одного раза для выбора определенной стратегии.
Использовать паттерн Strategy на практике можно, например, при выборе алгоритма шифрования:

public interface Algorithm {
  String crypt(String text, String key);
}

public class DESAlgorithm implements Algorithm {
  public String crypt(String text, String key) {
    String cryptedString = null;
    // тело алгоритма
    return cryptedString;
  }
}

public class RSAAlgorythm implements Algorythm {
  public String crypt(String text, String key) {
    String cryptedString = null;
    // тело алгоритма
    return cryptedString;
  }
}

public class Encryption {
  private Algorithm algorithm;

  public Encryption(Algorithm algorithm) {
    this.algorithm = algorithm;
  }

  public crypt(String text, String key) {
    return algorithm.crypt(text, key);
  }
}

public class Test {
  public static void main(String[] args) {
    String key = “key”;
    String text = “text”;
    int alg = 1;
    Encryption encryption;
    switch (alg) {
    case 0:
      encryption = new Encryption(new DESAlgorithm());
      break;
    case 1:
      encryption = new Encryption(new RSAAlgorithm());
      break;
    default:
      encryption = new Encryption(new DESAlgorithm());
    }
    String cryptedText = encryption.crypt(text, key);
  }
}

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

Жду ваших вопросов и комментариев.

11 Comments »

RSS feed for comments on this post. TrackBack URI



smile
March 9, 2006 #

Очень интересно.

Micik
October 20, 2006 #

String alg = 1; ??? :)
не мешало бы поправить опечатку

Moderated: спасибо, исправил

Slava
December 5, 2006 #

Ужасно! В настоящем ООП не должно быть if-в тем более case-в! В примере нет никакого паттерна стратегия! Жесть, а не пример.

December 6, 2006 #

Ну и где ты увидел if или case? Условный оператор фигурирует только в тестовом классе-примере и то только для того, чтоб задать какое-то условие для выбора нужной стратегии. Буду очень благодарен, если вместо фраз “ужасно” увижу конкретный пример. Спасибо.

чувак
April 26, 2007 #

Slava
ну вы товарисч ваабще чота не ф тему, ни каких веских доводов, фактов или обоснований, а лишь только “пук в лужу” и пропал….
Так все могут

Slava2
December 10, 2007 #

Поддержу теску - пример не совсем верный, желательно еще почитать банду 4х - там, кстати данный пример показан в качестве антипримера.

Правильный пример:

public class Encryption {
private Algorithm _algorithm;
public Encryption(Algorithm algorithm) {
_algorithm = algorithm;
}

public String Crypt(String text, String key) {
return _algorithm.crypt(text,key);
}
}

И соответственно, уже при создании объекта этого класса:
Encryption enc = new Encryption(new DESAlgorythm());
Encryption enc = new Encryption(new RSAAlgorythm());

и уже тогда:
String crypString = enc.Crypt(”String”,”Key”);
;)

kojak
January 21, 2008 #

Я смотрю, вам Батенька, учится и учится.
Конфузите читателей с вашим объяснением.
Предыдущий оратор выложил правильный пример использования.

January 21, 2008 #

Пост 2 года назад был написан… И тогда я учился, и сейчас учусь. Не делает ошибок только тот, кто вообще ничего не делает.
И все же, в который раз: кто-нибудь, покажите мне другой способ выбора алгоритма в runtime, кроме как конструкций типа if или switch. Намекаю, что обязательно будет место в коде, где необходимо условие выбора нужного алгоритма (стратегии). Главное свести количество таких мест к минимуму (1).

Victor Conovalov
January 31, 2008 #

a kak nascet takogo?

public abstract class Strategy {
public Strategy()
{
}
public abstract void doAlgoritm();
}

public class Context {

private Strategy strategy;
public final static int DEFAULT_ALGORITM = 0;
private Map algorimts = new HashMap() ;

public Context(Strategy strategy)
{
this.strategy = strategy;
algorimts.put(new Integer(DEFAULT_ALGORITM), strategy);
}

public void registerAlgoritm(int key, Strategy strategy)
{
algorimts.put(new Integer(key), strategy);
}

public void registerAlgoritm(Strategy strategy)
{
algorimts.put(new Integer(DEFAULT_ALGORITM), strategy);
}

public void ContextStrategy()
{
ContextStrategy(DEFAULT_ALGORITM);
}

public void ContextStrategy(int key)
{
algorimts.get(new Integer(key)).doAlgoritm();
}
}

January 31, 2008 #

Если зарегистрировано более одного алгоритма, как выбрать конкретный из них в runtime? Выбор основывается на сравнении, соответственно и на условии.

Есть конечно другой вариант. Пример - несколько приложений исползьзуют одно и то же API. Каждое приложение может иметь свою стратегию построения путей к файлам на файловой системе. Серверное приложение делает это через бины (читает из БД); GUI приложение - через свои настройки; тестовый фреймворк - на основании входящих данных. В этом случае выбор стратегии сделан заранее.

2 Victor: Но пример хороший, спасибо. Надо будет дополнить статью информацией о регистрации новых алгоритмов.

alexander
March 4, 2008 #

а почему собственно “В настоящем ООП не должно быть if-в тем более case-в” ?
интересует конкретный ответ.

Leave a comment

XHTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>