Паттерн «Стратегия» (Strategy)

Описание

Паттерн «Стратегия» позволяет определить семейство алгоритмов, инкапсулировать каждый из них и сделать их взаимозаменяемыми. Это позволяет изменять поведение объекта без изменения его класса.

Имеет схожую структуру с паттерном «Состояние». Построен на принципе «композиции», то есть на делегировании работы другим объектам.

«Стратегия» vs «Состояние»

В паттерне «Стратегия» различные стратегии работают независимо друг от друга и не взаимодействуют между собой.

В паттерне «Состояние» состояния могут менять друг друга, поскольку они связаны с общим объектом и управляют его переходами из одного состояния в другое.

Основные элементы паттерна:

  1. Контекст (Context): класс, который использует стратегию для выполнения определённой задачи. Контекст не знает, как работает конкретная стратегия, а просто вызывает метод, предоставленный стратегией.
  2. Интерфейс стратегии (Strategy): определяет интерфейс для всех возможных стратегий (алгоритмов).
  3. Конкретные стратегии (Concrete Strategy): классы, которые реализуют различные варианты поведения.

Пример: Оплата с помощью кредитных карт

У пользователя есть три кредитные карты: UnionPay, MasterCard и Visa. Пользователь делит покупку на три части и оплачивает каждую часть с помощью одной из карт.

Интерфейс стратегии:

Каждая кредитная карта реализует интерфейс PaymentStrategy, который имеет метод pay.

interface PaymentStrategy {
  pay(amount: number): boolean; // Метод возвращает true, если оплата успешна
}

Конкретные стратегии:

Каждая карта будет иметь баланс, и мы будем проверять, достаточно ли средств для оплаты. Если достаточно — оплата проходит успешно, иначе она отклоняется.

class UnionPay implements PaymentStrategy {
  private balance: number;

  constructor(balance: number) {
    this.balance = balance;
  }

  pay(amount: number): boolean {
    if (this.balance >= amount) {
      this.balance -= amount;
      console.log(`Оплата ${amount} с UnionPay прошла успешно. Остаток: ${this.balance}`);
      return true;
    } else {
      console.log(`Недостаточно средств на карте UnionPay.`);
      return false;
    }
  }
}

class MasterCard implements PaymentStrategy {
  private balance: number;

  constructor(balance: number) {
    this.balance = balance;
  }

  pay(amount: number): boolean {
    if (this.balance >= amount) {
      this.balance -= amount;
      console.log(`Оплата ${amount} с MasterCard прошла успешно. Остаток: ${this.balance}`);
      return true;
    } else {
      console.log(`Недостаточно средств на карте MasterCard.`);
      return false;
    }
  }
}

class Visa implements PaymentStrategy {
  private balance: number;

  constructor(balance: number) {
    this.balance = balance;
  }

  pay(amount: number): boolean {
    if (this.balance >= amount) {
      this.balance -= amount;
      console.log(`Оплата ${amount} с Visa прошла успешно. Остаток: ${this.balance}`);
      return true;
    } else {
      console.log(`Недостаточно средств на карте Visa.`);
      return false;
    }
  }
}

Контекст:

Контекст отвечает за процесс оплаты и может переключаться между разными стратегиями (картами) для оплаты каждой части покупки.

class PaymentProcessor {
  private strategy: PaymentStrategy;

  constructor(strategy: PaymentStrategy) {
    this.strategy = strategy;
  }

  setStrategy(strategy: PaymentStrategy): void {
    this.strategy = strategy;
  }

  processPayment(amount: number): boolean {
    return this.strategy.pay(amount);
  }
}

Использование:

Теперь создадим пример, в котором пользователь будет делить покупку на три части и оплачивать их с помощью трёх карт.

// Инициализация карт с определёнными балансами
const unionPayCard = new UnionPay(100);
const masterCard = new MasterCard(150);
const visaCard = new Visa(200);

// Инициализация процессора оплаты
const processor = new PaymentProcessor(unionPayCard);

// Сумма покупки
const totalAmount = 270; // Например, покупка стоит 270 единиц
const partAmount = totalAmount / 3; // Каждая карта оплатит 1/3

// Оплата первой части UnionPay
console.log('Оплата первой части:');
processor.setStrategy(unionPayCard);
processor.processPayment(partAmount);

// Оплата второй части MasterCard
console.log('Оплата второй части:');
processor.setStrategy(masterCard);
processor.processPayment(partAmount);

// Оплата третьей части Visa
console.log('Оплата третьей части:');
processor.setStrategy(visaCard);
processor.processPayment(partAmount);

Ссылки

Последние обновления

© 2023 — 2026 nbeam.ru