Шаблон состояния
Часть раздела Объектно-ориентированное программирование путешествия по Ruby на Coddy. Урок 49 из 57.
Шаблон состояние переносит поведение, зависящее от текущего состояния объекта, в отдельные объекты состояний. Главный объект, контекст, хранит одно состояние и перенаправляет ему вызовы; состояние отвечает и решает, какое состояние будет следующим:
class Red
def next_state
Green.new
end
def to_s
"red"
end
end
class Green
def next_state
Yellow.new
end
def to_s
"green"
end
end
class Yellow
def next_state
Red.new
end
def to_s
"yellow"
end
end
class TrafficLight
def initialize
@state = Red.new
end
def change
@state = @state.next_state
self
end
def to_s
"light is #{@state}"
end
end
light = TrafficLight.new
puts light
puts light.change
puts light.change.changeВывод:
light is red
light is green
light is redБез использования паттерна каждому методу контекста нужен case для значения статуса, а добавление нового состояния означает редактирование всех этих методов. При использовании объектов состояний каждое состояние представляет собой один класс, содержащий собственные правила:
# без паттерна
def can_go?
case @status
when :red then false
when :green then true
when :yellow then false
end
end
# с паттерном
def can_go?
@state.can_go?
endСостояния могут отклонять событие, которое им не подходит. Здесь черновик нельзя опубликовать напрямую; сначала он должен пройти проверку:
class Draft
def submit
Review.new
end
def publish
raise ArgumentError, "cannot publish a draft"
end
def to_s
"draft"
end
end
class Review
def publish
Published.new
end
def to_s
"in review"
end
end
class Published
def to_s
"published"
end
end
state = Draft.new
begin
state.publish
rescue ArgumentError => e
puts e.message
end
state = state.submit
state = state.publish
puts stateВывод:
cannot publish a draft
publishedОбщий базовый класс может задать для каждого состояния ответ по умолчанию, например отклонять каждое событие, чтобы каждое состояние определяло только принимаемые им события:
class State
def submit
raise ArgumentError, "cannot submit #{self}"
end
def approve
raise ArgumentError, "cannot approve #{self}"
end
end
class Review < State
def approve
Published.new
end
endЗадание
ЛегкоЗавершите светофор. Состояния Red, Green и Yellow имеют каждое по next_state (красный переходит в зелёный, зелёный — в жёлтый, жёлтый — в красный), can_go? (только зелёный) и to_s (цвет). TrafficLight начинается с красного, change переходит в следующее состояние, а status возвращает red: stop или green: go, запрашивая состояние.
Предоставленный код считывает команды change или status и выводит статус после каждой команды.
Ваш код должен находиться в файлах red.rb, green.rb, yellow.rb и traffic_light.rb. В main.rb находится предоставленный код ввода/вывода, и его нельзя редактировать.
Попробуйте сами
require_relative 'red'
require_relative 'green'
require_relative 'yellow'
require_relative 'traffic_light'
# Предоставленный код ввода/вывода: оставьте его как есть
input = []
while (line = gets)
input << line.chomp
end
light = TrafficLight.new
input.each do |cmd|
light.change if cmd == "change"
puts light.status
end
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Классы и объекты
Работа с файламиОпределение классовПеременные экземпляраМетоды и selfto_s и inspectПовторение — читательский билет4Инкапсуляция
Приватные методыЗащищённые методыПриватные сеттерыЗащита состоянияПовторение — торговый автомат7Полиморфизм и утиная типизация
ПолиморфизмУтиная типизацияАбстрактные методыcase и классыПовторение — способы оплаты10Шаблоны проектирования, часть 2
Делегирование с помощью ForwardableШаблон декоратораШаблон строителяШаблон состояния2Аксессоры и self
Чтение и записьПользовательские сеттерыself в методахИдентичность и равенствоПовторение — список контактов5Наследование
ПодклассыПереопределение методовВызов superis_a? и предкиПовторение — расчёт зарплаты сотрудников8Специальные методы
Равенство и хешированиеМетоды операторовИндексация и добавлениеПользовательские коллекцииПовторение — дроби11Проект: Управление библиотекой
Книги и читателиВыдача книг3Методы и переменные классов
Методы классовПеременные экземпляра классаКонстантыФабричные методыПовторение — коды купонов6Модули и примеси
Модули и includeРасширение объектовМодуль ComparableМодуль EnumerableПовторение — спортивная лига9Паттерны проектирования. Часть 1
Паттерн «Одиночка»Фабричный паттернПаттерн «Наблюдатель»Паттерн «Стратегия»Потренируйтесь самостоятельно: Онлайн-компилятор Ruby