Стан — це поведінковий патерн, що дозволяє динамічно змінювати поведінку об’єкта при зміні його стану.
Поведінки, які залежать від стану, переїзджають в окремі класи. Початковий клас зберігає посилання на один з таких об’єктів-станів та делегує йому роботу.
Складність:
Популярність:
Застосування: Патерн Стан часто використовують в Ruby для перетворення в об’єкти величезних стейт-машин, побудованих на операторах switch
.
Ознаки застосування патерна: Методи класу делегують роботу одному вкладеному об’єктові.
Концептуальний приклад
Цей приклад показує структуру патерна Стан , а саме — з яких класів він складається, які ролі ці класи виконують і як вони взаємодіють один з одним.
main.rb: Приклад структури патерна
# The Context defines the interface of interest to clients. It also maintains a
# reference to an instance of a State subclass, which represents the current
# state of the Context.
class Context
# A reference to the current state of the Context.
attr_accessor :state
private :state
# @param [State] state
def initialize(state)
transition_to(state)
end
# The Context allows changing the State object at runtime.
def transition_to(state)
puts "Context: Transition to #{state.class}"
@state = state
@state.context = self
end
# The Context delegates part of its behavior to the current State object.
def request1
@state.handle1
end
def request2
@state.handle2
end
end
# The base State class declares methods that all Concrete State should implement
# and also provides a backreference to the Context object, associated with the
# State. This backreference can be used by States to transition the Context to
# another State.
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
# Concrete States implement various behaviors, associated with a state of the
# Context.
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
# The client code.
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
Стан іншими мовами програмування