🎉 Ура! После трёх лет работы, я наконец выпустил английскую версию книги о паттернах! Вот она »
Стратегия

Стратегия на Ruby

Стратегия — это поведенческий паттерн, выносит набор алгоритмов в собственные классы и делает их взаимозаменимыми.

Другие объекты содержат ссылку на объект-стратегию и делегируют ей работу. Программа может подменить этот объект другим, если требуется иной способ решения задачи.

Подробней о Стратегии

Особенности паттерна на Ruby

Сложность:

Популярность:

Применимость: Стратегия часто используется в Ruby-коде, особенно там, где нужно подменять алгоритм во время выполнения программы. Начиная с Java 8, многие примеры стратегии можно заменить простыми lambda-выражениями.

Признаки применения паттерна: Класс делегирует выполнение вложенному объекту абстрактного типа или интерфейса.

Концептуальный пример

Этот пример показывает структуру паттерна Стратегия, а именно — из каких классов он состоит, какие роли эти классы выполняют и как они взаимодействуют друг с другом.

main.rb: Пример структуры паттерна

# Контекст определяет интерфейс, представляющий интерес для клиентов.
class Context
  # Контекст хранит ссылку на один из объектов Стратегии. Контекст не знает
  # конкретного класса стратегии. Он должен работать со всеми стратегиями через
  # интерфейс Стратегии.
  # @return [Strategy]
  attr_writer :strategy

  # Обычно Контекст принимает стратегию через конструктор, а также предоставляет
  # сеттер для её изменения во время выполнения.
  #
  # @param [Strategy] strategy
  def initialize(strategy)
    @strategy = strategy
  end

  # Обычно Контекст позволяет заменить объект Стратегии во время выполнения.
  #
  # @param [Strategy] strategy
  def strategy=(strategy)
    @strategy = strategy
  end

  # Вместо того, чтобы самостоятельно реализовывать множественные версии
  # алгоритма, Контекст делегирует некоторую работу объекту Стратегии.
  def do_some_business_logic
    # ...

    puts 'Context: Sorting data using the strategy (not sure how it\'ll do it)'
    result = @strategy.do_algorithm(%w[a b c d e])
    print result.join(',')

    # ...
  end
end

# Интерфейс Стратегии объявляет операции, общие для всех поддерживаемых версий
# некоторого алгоритма.
#
# Контекст использует этот интерфейс для вызова алгоритма, определённого
# Конкретными Стратегиями.
#
# @abstract
class Strategy
  # @abstract
  #
  # @param [Array] data
  def do_algorithm(_data)
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end
end

# Конкретные Стратегии реализуют алгоритм, следуя базовому интерфейсу Стратегии.
# Этот интерфейс делает их взаимозаменяемыми в Контексте.

class ConcreteStrategyA < Strategy
  # @param [Array] data
  #
  # @return [Array]
  def do_algorithm(data)
    data.sort
  end
end

class ConcreteStrategyB < Strategy
  # @param [Array] data
  #
  # @return [Array]
  def do_algorithm(data)
    data.sort.reverse
  end
end

# Клиентский код выбирает конкретную стратегию и передаёт её в контекст. Клиент
# должен знать о различиях между стратегиями, чтобы сделать правильный выбор.

context = Context.new(ConcreteStrategyA.new)
puts 'Client: Strategy is set to normal sorting.'
context.do_some_business_logic
puts "\n\n"

puts 'Client: Strategy is set to reverse sorting.'
context.strategy = ConcreteStrategyB.new
context.do_some_business_logic

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

Стратегия на других языках программирования

Стратегия на Java Стратегия на C# Стратегия на PHP Стратегия на Python Стратегия на Swift Стратегия на TypeScript