Стратегия — это поведенческий паттерн, выносит набор алгоритмов в собственные классы и делает их взаимозаменимыми.
Другие объекты содержат ссылку на объект-стратегию и делегируют ей работу. Программа может подменить этот объект другим, если требуется иной способ решения задачи.
Сложность:
Популярность:
Применимость: Стратегия часто используется в TypeScript-коде, особенно там, где нужно подменять алгоритм во время выполнения программы. Многие примеры стратегии можно заменить простыми анонимными функциями.
Признаки применения паттерна: Класс делегирует выполнение вложенному объекту абстрактного типа или интерфейса.
Концептуальный пример
Этот пример показывает структуру паттерна Стратегия , а именно — из каких классов он состоит, какие роли эти классы выполняют и как они взаимодействуют друг с другом.
index.ts: Пример структуры паттерна
/**
* Контекст определяет интерфейс, представляющий интерес для клиентов.
*/
class Context {
/**
* @type {Strategy} Контекст хранит ссылку на один из объектов Стратегии.
* Контекст не знает конкретного класса стратегии. Он должен работать со
* всеми стратегиями через интерфейс Стратегии.
*/
private strategy: Strategy;
/**
* Обычно Контекст принимает стратегию через конструктор, а также
* предоставляет сеттер для её изменения во время выполнения.
*/
constructor(strategy: Strategy) {
this.strategy = strategy;
}
/**
* Обычно Контекст позволяет заменить объект Стратегии во время выполнения.
*/
public setStrategy(strategy: Strategy) {
this.strategy = strategy;
}
/**
* Вместо того, чтобы самостоятельно реализовывать множественные версии
* алгоритма, Контекст делегирует некоторую работу объекту Стратегии.
*/
public doSomeBusinessLogic(): void {
// ...
console.log('Context: Sorting data using the strategy (not sure how it\'ll do it)');
const result = this.strategy.doAlgorithm(['a', 'b', 'c', 'd', 'e']);
console.log(result.join(','));
// ...
}
}
/**
* Интерфейс Стратегии объявляет операции, общие для всех поддерживаемых версий
* некоторого алгоритма.
*
* Контекст использует этот интерфейс для вызова алгоритма, определённого
* Конкретными Стратегиями.
*/
interface Strategy {
doAlgorithm(data: string[]): string[];
}
/**
* Конкретные Стратегии реализуют алгоритм, следуя базовому интерфейсу
* Стратегии. Этот интерфейс делает их взаимозаменяемыми в Контексте.
*/
class ConcreteStrategyA implements Strategy {
public doAlgorithm(data: string[]): string[] {
return data.sort();
}
}
class ConcreteStrategyB implements Strategy {
public doAlgorithm(data: string[]): string[] {
return data.reverse();
}
}
/**
* Клиентский код выбирает конкретную стратегию и передаёт её в контекст. Клиент
* должен знать о различиях между стратегиями, чтобы сделать правильный выбор.
*/
const context = new Context(new ConcreteStrategyA());
console.log('Client: Strategy is set to normal sorting.');
context.doSomeBusinessLogic();
console.log('');
console.log('Client: Strategy is set to reverse sorting.');
context.setStrategy(new ConcreteStrategyB());
context.doSomeBusinessLogic();
Output.txt: Результат выполнения
Client: Strategy is set to normal sorting.
Context: Sorting data using the strategy (not sure how it'll do it)
a,b,c,d,e
Client: Strategy is set to reverse sorting.
Context: Sorting data using the strategy (not sure how it'll do it)
e,d,c,b,a