December
2005
Паттерн 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 setAlgorithm(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 = new Encryption(new DESAlgorithm());
String cryptedText = encryption.crypt(text, key);
}
}
Далее, если нам в некотором участке кода понадобится поменять стратегию криптования, допустим по какому-то условию, можно сделать следующее:
...
boolean needToChange = true;
...
if (needToChange)
encryption.setAlgorithm(new RSAAlgorithm());
...
Ну вот и все.
Паттерн Стратегия часто используется вместе с другими паттернами проектирования. Но и сам по себе он будет достаточно полезен в боль?ом количестве случаев.
Жду ва?их вопросов и комментариев.
25 Comments »
RSS feed for comments on this post. TrackBack URI
Ужасно! В настоящем ООП не должно быть if-в тем более case-в! В примере нет никакого паттерна стратегия! Жесть, а не пример.
Ну и где ты увидел if или case? Условный оператор фигурирует только в тестовом классе-примере и то только для того, чтоб задать какое-то условие для выбора нужной стратегии. Буду очень благодарен, если вместо фраз “ужасно” увижу конкретный пример. Спасибо.
Slava
ну вы товарисч ваабще чота не ф тему, ни каких веских доводов, фактов или обоснований, а ли?ь только “пук в лужу” и пропал….
Так все могут
Поддержу теску - пример не совсем верный, желательно еще почитать банду 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”);
![]()
Я смотрю, вам Батенька, учится и учится.
Конфузите читателей с ва?им объяснением.
Предыдущий оратор выложил правильный пример использования.
Пост 2 года назад был написан… ? тогда я учился, и сейчас учусь. Не делает о?ибок только тот, кто вообще ничего не делает.
? все же, в который раз: кто-нибудь, покажите мне другой способ выбора алгоритма в runtime, кроме как конструкций типа if или switch. Намекаю, что обязательно будет место в коде, где необходимо условие выбора нужного алгоритма (стратегии). Главное свести количество таких мест к минимуму (1).
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();
}
}
Если зарегистрировано более одного алгоритма, как выбрать конкретный из них в runtime? Выбор основывается на сравнении, соответственно и на условии.
Есть конечно другой вариант. Пример - несколько приложений исползьзуют одно и то же API. Каждое приложение может иметь свою стратегию построения путей к файлам на файловой системе. Серверное приложение делает это через бины (читает из БД); GUI приложение - через свои настройки; тестовый фреймворк - на основании входящих данных. В этом случае выбор стратегии сделан заранее.
2 Victor: Но пример хоро?ий, спасибо. Надо будет дополнить статью информацией о регистрации новых алгоритмов.
а почему собственно “В настоящем ООП не должно быть if-в тем более case-в” ?
интересует конкретный ответ.
Когда сам начал изучать паттерны, тоже ?ло отторжение таких вот высосаных примеров. Но потом когда начинае?ь кодить, доходи?ь до этого сам, смотри?ь и думае?ь: е-моё, паттерн вылепился. ? в след. раз уже намного проще и быстрее к похожему варианту приходи?ь.
Я тоже не вижу, причем здесь вобще к паттерну case в теле функции main. Собственно, реализация паттерна локализована совсем в другом месте. Можно конечно присобачить еще пару десятков классов для выбора стратегии из оракла, но зачем?… Увидел case - кричи “пожар”. Это похоже на недопонимание вопроса.
А чего никто не упомянул про динамическую загрузку то?
Это раз.
Т.е. вообще строго говоря хоро?им примером было бы чтото типа:
String selectedStratagy = … ; // тут получили откудато стратегию которую нада юзать.
Algoritm al = Class.forName(”"+selectedStratagy).newInstance(); //”" - сюда можно дописать чтонить.
al.crypt(param1, param2);
————————-
? два.
Вопрос был про то как уйти от if-else, и хоть в моем примере - их нет, по сути они вынесены на более высокий уровень. Так как гдето-то выбирается имя для selectedStratagy.
Этой теме посвещена целая “Теория приянтия ре?ения”, раздел математики.
Выбор конкретной методики поиска пути ре?ения (тоесть в на?ем случае - то как мы выбираем алгоритм) я считаю зависит от задачи.
? если гдето это будет мат функция, возвращающая каким либо образом идентификатор, в другом месте это может быть например набор правил. В третьем это может быть вообще нейро сеть, которая на выходе выдаст идентификатор алгоритма.
Тоесть на самом деле - универсального ответа - как избавится от if - else - нет. Ессно в рамках этого вопроса.
Это в _идеальном_ ООП не должно быть if-else-case и т.д., а идеального нету ничего. Возьмите исходники Java библиотек, тоже ведь не идеально написаны. Но и не дети то писали их.
Афтар тебе 3 момента
1. Установка код-ки RSS-ленты твоего сайта
2-ой Какой первоисточник читаемого материала?
3. Хоче?ь подескутировать по теме?
Обращение к Славам.
если такие умные сделали бы этот топик сами.
а создателю топика, огромное спасибо, что для кого - то стараеца)
GS
тока надо добавить хэ? - таблицу, для хранения типа стратегии и его айди, т.е. цифры которую выбирали через кейс
Кстати… у кого-то получалось обойтись без if else вообще? Покажите пример программы ![]()
Maxim, Вы на примере какого языка программирования ждете код? На PHP, например, это делается через подстановку переменной в имя класса, от которого создаем объект для стратегии.
вроде сносный патерн, только чегото нехватает..
думаю неплохо было бы обьединить его с “фабрикой”
на практике бывает небходимо не только одну функцию дергать.. скажем в одном случае нужно функ1 и функ2 последовательно выполнить а в втором функ1 и функ3 как тогда быть?
interface Algorithm {
String crypt(String text, String key);
}
class DESAlgorithm implements Algorithm {
public String crypt(String text, String key) {
String cryptedString = null;
// тело алгоритма
return cryptedString;
}
}
class RSAAlgorithm implements Algorithm {
public String crypt(String text, String key) {
String cryptedString = null;
// тело алгоритма
return cryptedString;
}
}
class Test {
static void encrypt(Algorithm a, String text,
String key) {
a.crypt(text, key);
}
public static void main(String[] args) {
String key = "key";
String text = "text";
encrypt(new DESAlgorithm(), text, key);
encrypt(new RSAAlgorithm(), text, key);
}
}
Nice article with so understanding point of wiev. Thanls a lot!
Фирма продает тосол А40М , антифриз Platinum по оптовым ценам.
учитесь, учитесь и учитесь, как завещал великий …материалы по нефти и газу
Отличная статья и удобный паттерн.
Но как бы вы поступили, если стратегии необходимо обращаться к полям класса? Вот например:
public class Student implements Comparable {
private String name;
private String year;
private SortStrategy sortStrategy;
public Student(String name, String year, SortStrategy sortStrategy) { … }
@Owerride
public int compareTo(Object o) {
return sortStrategy.compareTo(Object o);
}
}
И нам надо, чтобы мы могли сортировать студентов по имени или по году, в зависимости от того, какая у нас стратегия. Может я туплю, но ничего не могу придумать.