Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

เชี่ยวชาญ State Machines ใน Ruby ด้วย AASM: คู่มือปฏิบัติ

วันนี้คุณจะได้เรียนรู้เกี่ยวกับ state machines (เครื่องจักรสถานะ) วิธีทำงาน และวิธีใช้ในโปรเจกต์ Ruby ด้วย gem AASM

ตอนนี้:

นึกภาพไฟจราจร...

มันสามารถเป็น แดง เขียว หรือ เหลือง

เมื่อมันเปลี่ยนสี สี ถัดไป จะขึ้นอยู่กับ สี ปัจจุบัน

เชี่ยวชาญ State Machines ใน Ruby ด้วย AASM: คู่มือปฏิบัติ

สมมติว่านี่คือแบบที่ออกเสียงสำหรับคนตาบอด รู้ว่าจะข้ามได้เมื่อไหร่

ตอนนี้:

คุณกำลังเขียนซอฟต์แวร์สำหรับสิ่งนี้

คุณจะรู้ยังไงว่าเล่นเสียงอะไรทุกครั้ง และสีไหนควรเป็นถัดไป?

คุณอาจเขียน if statements แบบนี้:

if @light.state == "green"
  @light.play_green_sound
end
if @light.state == "green"
  @light.change_to_yellow
end
# ...

โค้ดตรวจสอบสถานะนี้จะกระจายอยู่ทั่วไป!

เราจะปรับปรุงอย่างไร?

ถ้าคุณนำหลักการออกแบบเชิงวัตถุ (Object-Oriented Design principles) ไปใช้ คุณจะค้นพบใหม่ State Design Pattern

State Design Pattern คืออะไร?

State Design Pattern เป็นหนึ่งวิธีในการ implement state machine

คุณต้องการ 3 ส่วนประกอบ:

  • คลาส Context คลาสนี้รู้ว่าสถานะปัจจุบันคืออะไร
  • คลาส State คลาสนี้กำหนดเมธอดที่ควร implement โดยสถานะแต่ละตัว
  • คลาสหนึ่งสำหรับแต่ละสถานะ คลาสเหล่านี้จะสืบทอดจากคลาส State

ในตัวอย่างไฟจราจร Context คือ TrafficLight เอง

และสถานะคือ Green, Red และ Yellow

ทุกสถานะจะรู้ว่าต้องทำอะไร

ประโยชน์ใหญ่?

ทุกสถานะรู้จักตัวเอง ดังนั้นไม่ต้องตรวจสอบสถานะปัจจุบัน แปลว่า conditional statements น้อยลง ซึ่งมักเป็นแหล่งความซับซ้อน

การ Implement ไฟจราจร

มา看看โค้ดสำหรับการ implement จริงของรูปแบบนี้

นี่คือ TrafficLight:

class TrafficLight
  def initialize
    @state = nil
  end

  def next_state(klass = Green)
    @state = klass.new(self)
    @state.beep
    @state.start_timer
  end
end

นี่คือ State พื้นฐาน:

class State
  def initialize(light)
    @light = light
  end

  def beep
  end

  def next_state
  end

  def start_timer
  end
end

ใช่ เมธอด 3 ตัวนี้ว่างเปล่า

เป็นข้อตกลงทั่วไปในภาษาโปรแกรมอื่น (อย่าง Java) ที่จะกำหนด "interface" นี้ แตไม่ค่อยนิยมใน Ruby

นี่อยู่ที่นี่เพื่อการสาธิต

อย่างไรก็ตาม เรายังต้องการแชร์เมธอด initialize ระหว่างทุกสถานะ เพราะทุกอย่างต้องการ context (ออบเจ็กต์ TrafficLight) เพื่อส่งสัญญาณ การเปลี่ยนสถานะ

ตอนนี้:

3 สถานะดูคล้ายกันมาก ผมจะแสดงโค้ดสำหรับแค่หนึ่ง

นี่คือสถานะ Green:

class Green < State
  def beep
    puts "Color is now green"
  end

  def next_state
    @light.next_state(Yellow)
  end

  def start_timer
    sleep 5; next_state
  end
end

ทุกสถานะรู้ว่าจะเปลี่ยนไปสถานะไหนและเมื่อไหร่

ตัวอย่าง AI Game

คุณสามารถใช้ state machine เพื่อแก้เกมที่ขึ้นอยู่กับสถานะปัจจุบัน เช่น RubyWarrior

ใน RubyWarrior คุณได้รับออบเจ็กต์ผู้เล่นและกระดาน

เป้าหมายคือ:

  • เอาชนะศัตรูทั้งหมดบนกระดาน
  • ไปถึงทางออกขณะที่ HP อยู่เหนือ 0

คุณทำการเคลื่อนไหวได้ทีละครั้ง และต้องเลือกที่ดี หากต้องการผ่านด่าน

การดูสถานะปัจจุบันช่วยให้คุณเลือกได้

นั่นคือเหตุผลที่ state machine เป็นโซลูชันที่ดี

ตัวอย่าง:

class Attacking < State
  def play(warrior)
    warrior.attack!
    @player.set_state(Healing) unless enemy_found?(warrior)
  end
end

นี่คือหนึ่งในสถานะที่ warrior ของเราอาจอยู่ เมื่อไม่มีศัตรูในสายตา เราเปลี่ยนไปสถานะ Healing เพื่อฟื้นฟูจากความเสียหาย

การใช้ Gem AASM

หากคุณต้องการติดตามสถานะปัจจุบัน ในขณะที่รับรองว่าการเปลี่ยนผ่าน (transitions) ถูกต้อง คุณสามารถใช้ state machine gem อย่าง AASM

Gem นี้สร้างขึ้นรอบไอเดียของ events (เหมือนกดสวิตช์ไฟ) ที่กระตุ้นการเปลี่ยนผ่านไปสถานะอื่น

ตัวอย่าง:

require 'aasm'
class Light
  include AASM
  aasm do
    state :on, :off
    event :switch do
      transitions :from => :on, :to => :off, :if => :on?
      transitions :from => :off, :to => :on, :if => :off?
    end
  end
end

วิธีใช้คลาสนี้:

light = Light.new
p light.on? # true
light.switch
p light.on? # false

การใช้ state machine นี้ คุณสามารถเปลี่ยนไปสถานะ "on" ได้ก็ต่อเมื่อสถานะปัจจุบันคือ "off" คุณยังสามารถมี callbacks (before/after) หลายตัว เพื่อรันโค้ดเฉพาะระหว่างการเปลี่ยนสถานะ

Callbacks เหล่านี้อาจรวมถึง:

  • ส่งอีเมล
  • บันทึกการเปลี่ยนสถานะ (logging)
  • อัปเดตแดชบอร์ดตรวจสอบแบบเรียลไทม์

นอกจากนี้ AASM มีตัวเลือกในการบันทึกสถานะปัจจุบันลงฐานข้อมูลด้วย ActiveRecord

วิดีโอ AASM Gem

สรุป

คุณได้เรียนรู้เกี่ยวกับ state machines, state design pattern และ gem AASM! เรียนรู้ต่อไปด้วยการสมัคร newsletter Ruby ของผม (7000+ subscribers) เพื่อ ไม่พลาดบทความใหม่และเคล็ดลับ Ruby 獨家

ตอนนี้เวลาฝึกกับแนวคิดใหม่ๆ 🙂

ขอบคุณที่อ่านครับ!