Стратегия (шаблон проектирования)

Материал из 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


bg:Стратегия (шаблон)

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:策略模式

Личные инструменты

Served in 0.213 secs.