- Strategy
-
Название Стратегия Английское название Strategy Диаграмма Тип поведенческий Назначение позволяет использовать различные бизнес-правила или алгоритмы в зависимости от контекста. Применяется в случаях в одном и том же случае, в зависимости от текущего состояния системы или её окружения, используются различные алгоритмы. Плюсы - инкапсуляция реализации различных алгоритмов, система становится независимой от возможных изменений бизнес-правил;
- вызов всех алгоритмов одним стандартным образом;
- отказ от использования переключателей и/или условных операторов.
Минусы создание дополнительных классов Родственные шаблоны Мост, Шаблонный метод, Адаптер Стратегия, Strategy — поведенческий шаблон проектирования, предназначенный для определения семейства алгоритмов, инкапсуляции каждого из них и обеспечения их взаимозаменяемости. Это позволяет выбирать алгоритм путем определения соответствующего класса. Шаблон Strategy позволяет менять выбранный алгоритм независимо от объектов-клиентов, которые его используют.
Содержание
Основные характеристики
Задача
Выбор алгоритма, который следует применить, в зависимости от типа выдавшего запрос клиента или обрабатываемых данных. Если используется правило, которое не подвержено изменениям, нет необходимости обращаться к шаблону «стратегия».
Мотивы
- Программа должна обеспечивать различные варианты алгоритма или поведения
- Нужно изменять поведение каждого экземпляра класса
- Необходимо изменять поведение объектов на стадии выполнения
- Введение интерфейса позволяет классам-клиентам ничего не знать о классах, реализующих этот интерфейс и инкапсулирующих в себе конкретные алгоритмы
Способ решения
Отделение процедуры выбора алгоритма от его реализации. Это позволяет сделать выбор на основании контекста.
Участники
- Класс
Strategy
определяет как будут использоваться различные алгоритмы. - Конкретные классы
ConcreteStrategy
реализуют эти различные алгоритмы. - Класс
Context
использует конкретные классыConcreteStrategy
посредством ссылки на конкретный тип абстрактного классаStrategy
. КлассыStrategy
иContext
взаимодействуют с целью реализации выбранного алгоритма (в некоторых случаях классуStrategy
требуется посылать запросы классуContext
). КлассContext
пересылает классуStrategy
запрос, поступивший от его класса-клиента.
Следствия
- Шаблон Strategy определяет семейство алгоритмов.
- Это позволяет отказаться от использования переключателей и/или условных операторов.
- Вызов всех алгоритмов должен осуществляться стандартным образом (все они должны иметь одинаковый интерфейс).
Реализация
Класс, который использует алгоритм (
Context
), включает абстрактный класс (Strategy
), обладающий абстрактным методом, определяющим способ вызова алгоритма. Каждый производный класс реализует один требуемый вариант алгоритма.Замечание: метод вызова алгоритма не должен быть абстрактным, если требуется реализовать некоторое поведение, принимаемое по умолчанию.
Примеры
Примеры на Javascript
// "интерфейс" Strategy function Strategy() { this.exec = function() {}; }; // реализации Strategy // показ ссобщения в статусной строке браузера // (поддерживается не всеми браузерами) function StrategyWindowStatus() { this.exec = function(message) { window.status = message; }; }; StrategyWindowStatus.prototype = new Strategy(); StrategyWindowStatus.prototype.constructor = StrategyWindowStatus; // показ сообщения с помощью попапа // (может быть заблокировано браузером) function StrategyNewWindow() { this.exec = function(message) { var win = window.open("", "_blank"); win.document.write("<html>"+ message +"</html>"); }; }; StrategyNewWindow.prototype = new Strategy(); StrategyNewWindow.prototype.constructor = StrategyNewWindow; // показ сообщения с помощью модального окна function StrategyAlert() { this.exec = function(message) { alert(message); }; }; StrategyAlert.prototype = new Strategy(); StrategyAlert.prototype.constructor = StrategyAlert; // Context function Context(strategy) { this.exec = function(message) { strategy.exec(message); }; } // Использование var showInWindowStatus = new Context( new StrategyWindowStatus() ); var showInNewWindow = new Context( new StrategyNewWindow() ); var showInAlert = new Context( new StrategyAlert() ); showInWindowStatus.exec("сообщение"); showInNewWindow.exec("сообщение"); showInAlert.exec("сообщение");
Пример с использованием динамических (first-class) функций
function Context(fn) { this.exec = function() { fn.apply(this, arguments || []); }; }; var showInWindowStatus = new Context( function(message) { window.status = message; } ); var showInNewWindow = new Context( function(message) { var win = window.open("", "_blank"); win.document.write("<html>"+ message +"</html>"); } ); var showInAlert = new Context( function(message) { alert(message); } ); showInWindowStatus.exec("сообщение"); showInNewWindow.exec("сообщение"); showInAlert.exec("сообщение");
Примеры на PHP5
abstract class FileNamingStrategy{ abstract function createLinkName($filename); } class ZipFileNamingStrategy extends FileNamingStrategy{ function createLinkName($filename){ return "http://downloads.foo.bar/$filename.zip"; } } class TarGzFileNamingStrategy extends FileNamingStrategy{ function createLinkName($filename){ return "http://downloads.foo.bar/$filename.tar.gz"; } } if(strstr($_SERVER["HTTP_USER_AGENT"], "Win")){ $fileNamingObj = new ZipFileNamingStrategy(); } else { $fileNamingObj = new TarGzFileNamingStrategy(); } $calc_filename = $fileNamingObj->createLinkName("Calc101"); $stat_filename = $fileNamingObj->createLinkName("Stat2000"); print <<<EOF <h1>The following is a list of great downloads</h1><br /> <a href="$calc_filename">A great calculator</a><br /> <a href="$stat_filename">The best statistics application</a> EOF;
Источники информации
- Шаллоуей, Алан, Тротт, Джейм, Р. Шаблоны проектирования. Новый подход к объектно-ориентированному анализу и проектированию: Пер. с англ. —М.: Издательский дом «Вильямс», 2002. —288 с. ISBN 5-8459-0301-7
- Grand, Mark. Шаблоны проектирования в Java: Пер. с англ. — М.: Новое знание, 2004. — 559 с. ISBN 5-94735-047-5
Wikimedia Foundation. 2010.