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

Состояние на Ruby

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

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

Подробней о Состоянии

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

Сложность:

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

Применимость: Паттерн Состояние часто используют в Ruby для превращения в объекты громоздких стейт-машин, построенных на операторах switch.

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

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

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

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

# Контекст определяет интерфейс, представляющий интерес для клиентов. Он также
# хранит ссылку на экземпляр подкласса Состояния, который отображает текущее
# состояние Контекста.
#
# @abstract
class Context
  # Ссылка на текущее состояние Контекста.
  # @return <a href="/ru/design-patterns/state">Состояние</a>
  attr_accessor :state
  private :state

  # @param <a href="/ru/design-patterns/state">Состояние</a> state
  def initialize(state)
    transition_to(state)
  end

  # Контекст позволяет изменять объект Состояния во время выполнения.
  #
  # @param <a href="/ru/design-patterns/state">Состояние</a> state
  def transition_to(state)
    puts "Context: Transition to #{state.class}"
    @state = state
    @state.context = self
  end

  # Контекст делегирует часть своего поведения текущему объекту Состояния.

  def request1
    @state.handle1
  end

  def request2
    @state.handle2
  end
end

# Базовый класс Состояния объявляет методы, которые должны реализовать все
# Конкретные Состояния, а также предоставляет обратную ссылку на объект
# Контекст, связанный с Состоянием. Эта обратная ссылка может использоваться
# Состояниями для передачи Контекста другому Состоянию.
#
# @abstract
class State
  attr_accessor :context

  # @abstract
  def handle1
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end

  # @abstract
  def handle2
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end
end

# Конкретные Состояния реализуют различные модели поведения, связанные с
# состоянием Контекста.

class ConcreteStateA < State
  def handle1
    puts 'ConcreteStateA handles request1.'
    puts 'ConcreteStateA wants to change the state of the context.'
    @context.transition_to(ConcreteStateB.new)
  end

  def handle2
    puts 'ConcreteStateA handles request2.'
  end
end

class ConcreteStateB < State
  def handle1
    puts 'ConcreteStateB handles request1.'
  end

  def handle2
    puts 'ConcreteStateB handles request2.'
    puts 'ConcreteStateB wants to change the state of the context.'
    @context.transition_to(ConcreteStateA.new)
  end
end

# Клиентский код.

context = Context.new(ConcreteStateA.new)
context.request1
context.request2

output.txt: Результат выполнения

Context: Transition to ConcreteStateA
ConcreteStateA handles request1.
ConcreteStateA wants to change the state of the context.
Context: Transition to ConcreteStateB
ConcreteStateB handles request2.
ConcreteStateB wants to change the state of the context.
Context: Transition to ConcreteStateA

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

Состояние на Java Состояние на C# Состояние на PHP Состояние на Python Состояние на Swift Состояние на TypeScript