Menu
Coddy logo textTech

상태 패턴

Coddy Ruby 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 57개 중 49번째.

상태 패턴은 객체의 현재 상태에 따라 달라지는 동작을 별도의 상태 객체로 옮깁니다. 주요 객체인 컨텍스트는 하나의 상태를 보유하고 호출을 해당 상태로 전달합니다. 상태는 응답하고 다음에 올 상태를 결정합니다:

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
challenge icon

챌린지

쉬움

신호등을 완성하세요. Red, Green, Yellow 상태에는 각각 next_state(red에서 green으로, green에서 yellow로, yellow에서 red로 이동), can_go?(green일 때만 가능), to_s(색상)가 있습니다. TrafficLight는 red에서 시작하고, 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
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 Ruby 컴파일러