Стратегия (шаблон проектирования)
Материал из Seo Wiki - Поисковая Оптимизация и Программирование
| Название | Стратегия |
|---|---|
| Английское название | Strategy |
| Диаграмма | |
| Тип | поведенческий |
| Назначение | позволяет использовать различные бизнес-правила или алгоритмы в зависимости от контекста. |
| Применяется в случаях | в одном и том же случае, в зависимости от текущего состояния системы или её окружения, используются различные алгоритмы. |
| Плюсы |
|
| Минусы | создание дополнительных классов |
| Родственные шаблоны | Мост, Шаблонный метод, Адаптер |
Стратегия, Strategy — поведенческий шаблон проектирования, предназначенный для определения семейства алгоритмов, инкапсуляции каждого из них и обеспечения их взаимозаменяемости. Это позволяет выбирать алгоритм путем определения соответствующего класса. Шаблон Strategy позволяет менять выбранный алгоритм независимо от объектов-клиентов, которые его используют.
Содержание |
[править] Основные характеристики
[править] Задача
Выбор алгоритма, который следует применить, в зависимости от типа выдавшего запрос клиента или обрабатываемых данных. Если используется правило, которое не подвержено изменениям, нет необходимости обращаться к шаблону «стратегия».
[править] Мотивы
- Программа должна обеспечивать различные варианты алгоритма или поведения
- Нужно изменять поведение каждого экземпляра класса
- Необходимо изменять поведение объектов на стадии выполнения
- Введение интерфейса позволяет классам-клиентам ничего не знать о классах, реализующих этот интерфейс и инкапсулирующих в себе конкретные алгоритмы
[править] Способ решения
Отделение процедуры выбора алгоритма от его реализации. Это позволяет сделать выбор на основании контекста.
[править] Участники
- Класс
Strategyопределяет как будут использоваться различные алгоритмы. - Конкретные классы
ConcreteStrategyреализуют эти различные алгоритмы. - Класс
Contextиспользует конкретные классыConcreteStrategyпосредством ссылки на конкретный тип абстрактного классаStrategy. КлассыStrategyиContextвзаимодействуют с целью реализации выбранного алгоритма (в некоторых случаях классуStrategyтребуется посылать запросы классуContext). КлассContextпересылает классуStrategyзапрос, поступивший от его класса-клиента.
[править] Следствия
- Шаблон Strategy определяет семейство алгоритмов.
- Это позволяет отказаться от использования переключателей и/или условных операторов.
- Вызов всех алгоритмов должен осуществляться стандартным образом (все они должны иметь одинаковый интерфейс).
[править] Реализация
Класс, который использует алгоритм (Context), включает абстрактный класс (Strategy), обладающий абстрактным методом, определяющим способ вызова алгоритма. Каждый производный класс реализует один требуемый вариант алгоритма.
Замечание: метод вызова алгоритма не должен быть абстрактным, если требуется реализовать некоторое поведение, принимаемое по умолчанию.
[править] Примеры
[править] Пример на C#
using System; namespace DesignPatterns.Behavioral.Strategy { /// <summary> /// Интерфейс «Стратегия» определяет функциональность (в данном примере это метод /// <see cref="Algorithm">Algorithm</see>), которая должна быть реализована /// конкретными классами стратегий. Другими словами, метод интерфейса определяет /// решение некой задачи, а его реализации в конкретных классах стратегий определяют, /// КАК, КАКИМ ПУТЁМ эта задача будет решена. /// </summary> public interface IStrategy { void Algorithm(); } /// <summary> /// Первая конкретная реализация-стратегия. /// </summary> public class ConcreteStrategy1 : IStrategy { public void Algorithm() { Console.WriteLine("Выполняется алгоритм стратегии 1."); } } /// <summary> /// Вторая конкретная реализация-стратегия. /// Реализаций может быть сколько угодно много. /// </summary> public class ConcreteStrategy2 : IStrategy { public void Algorithm() { Console.WriteLine("Выполняется алгоритм стратегии 2."); } } /// <summary> /// Контекст, использующий стратегию для решения своей задачи. /// </summary> public class Context { /// <summary> /// Ссылка на интерфейс <see cref="IStrategy">IStrategy</see> /// позволяет автоматически переключаться между конкретными реализациями /// (другими словами, это выбор конкретной стратегии). /// </summary> private IStrategy _strategy; /// <summary> /// Конструктор контекста. /// Инициализирует объект стратегией. /// </summary> /// <param name="strategy"> /// Стратегия. /// </param> public Context(IStrategy strategy) { _strategy = strategy; } /// <summary> /// Метод для установки стратегии. /// Служит для смены стратегии во время выполнения. /// В C# может быть реализован также как свойство записи. /// </summary> /// <param name="strategy"> /// Новая стратегия. /// </param> public void SetStrategy(IStrategy strategy) { _strategy = strategy; } /// <summary> /// Некоторая функциональность контекста, которая выбирает /// стратегию и использует её для решения своей задачи. /// </summary> public void ExecuteOperation() { _strategy.Algorithm(); } } /// <summary> /// Класс приложения. /// В данном примере выступает как клиент контекста. /// </summary> public static class Program { /// <summary> /// Точка входа в программу. /// </summary> public static void Main() { // Создём контекст и инициализируем его первой стратегией. Context context = new Context(new ConcreteStrategy1()); // Выполняем операцию контекста, которая использует первую стратегию. context.ExecuteOperation(); // Заменяем в контексте первую стратегию второй. context.SetStrategy(new ConcreteStrategy2()); // Выполняем операцию контекста, которая теперь использует вторую стратегию. context.ExecuteOperation(); } } }
[править] Примеры на 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
| Файл:Soft template.gif | Это незавершённая статья о программном обеспечении. Вы можете помочь проекту, исправив и дополнив её. |
ca:Patró estratègia cs:Strategy de:Strategie (Entwurfsmuster) en:Strategy pattern es:Strategy (patrón de diseño) fr:Stratégie (patron de conception) it:Strategy pattern ja:Strategy パターン pl:Strategia (wzorzec projektowy) pt:Strategy vi:Strategy pattern zh:策略模式