Hôm nay, bạn sẽ tìm hiểu về các máy trạng thái, cách chúng hoạt động và cách sử dụng chúng trong các dự án Ruby của bạn với AASM gem.
Bây giờ :
Hãy tưởng tượng đèn giao thông…
Nó có thể có màu đỏ, xanh lá cây hoặc vàng.
Khi nó thay đổi màu sắc, tiếp theo màu dựa trên hiện tại một.
Giả sử rằng đây là loại hình tạo ra tiếng vang cho người mù để họ biết khi nào họ có thể vượt qua.
Bây giờ :
Bạn đang viết phần mềm cho thứ này.
Làm thế nào để bạn biết âm thanh nào sẽ phát mỗi lần và màu gì sẽ tiếp theo?
Bạn có thể viết một số câu lệnh if như sau:
if @light.state == "green" @light.play_green_sound end if @light.state == "green" @light.change_to_yellow end # ...
Mã kiểm tra trạng thái này sẽ ở khắp nơi!
Chúng tôi có thể cải thiện điều này bằng cách nào?
Nếu bạn áp dụng các nguyên tắc Thiết kế hướng đối tượng, bạn sẽ khám phá lại Mẫu thiết kế trạng thái.
Mẫu thiết kế trạng thái là gì?
State Design Pattern là một cách để triển khai máy trạng thái.
Bạn sẽ cần 3 thành phần :
- Một
Context
lớp này, lớp này biết trạng thái hiện tại là gì - Một
State
lớp, lớp này xác định các phương thức sẽ được triển khai bởi các trạng thái riêng lẻ - Một lớp cho mọi tiểu bang. Các lớp này sẽ kế thừa từ
State
lớp học
Trong ví dụ về đèn giao thông của chúng tôi, ngữ cảnh là TrafficLight
chính nó.
Và các trạng thái là Green
, Red
&Yellow
.
Mọi tiểu bang sẽ biết phải làm gì.
Lợi ích lớn ?
Mọi trạng thái đều tự biết nên không cần kiểm tra trạng thái hiện tại. Điều này chuyển thành các câu lệnh ít điều kiện hơn, thường là một nguồn phức tạp.
Triển khai đèn giao thông
Hãy xem mã để triển khai thực tế mẫu này.
Đây là TrafficLight
:
class TrafficLight def initialize @state = nil end def next_state(klass = Green) @state = klass.new(self) @state.beep @state.start_timer end end
Đây là State
cơ sở :
class State def initialize(light) @light = light end def beep end def next_state end def start_timer end end
Có, 3 phương thức này trống.
Đó là quy ước chung trong các ngôn ngữ lập trình khác (như Java) để xác định “giao diện” này, nhưng nó không phổ biến trong Ruby.
Đây là đây cho mục đích trình diễn.
Tuy nhiên, chúng tôi vẫn muốn chia sẻ initialize
giữa tất cả các trạng thái vì tất cả chúng đều cần ngữ cảnh (TrafficLight
đối tượng) để báo hiệu thay đổi trạng thái .
Bây giờ :
3 trạng thái trông rất giống nhau, vì vậy tôi sẽ chỉ cho bạn mã của một trong số chúng.
Đây là Green
trạng thái:
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
Mọi trạng thái đều biết cách thức và thời điểm chuyển sang trạng thái tiếp theo.
Ví dụ về trò chơi AI
Bạn có thể sử dụng máy trạng thái để giải quyết các trò chơi phụ thuộc vào trạng thái hiện tại, chẳng hạn như RubyWarrior.
Trong RubyWarrior, bạn được cung cấp một đối tượng người chơi và một bảng.
Mục tiêu là :
- Đánh bại tất cả kẻ thù trên bàn cờ
- Tiếp cận lối ra trong khi giữ HP của bạn trên 0
Bạn có thể thực hiện từng bước một và bạn phải lựa chọn tốt nếu muốn hoàn thành cấp độ.
Xem xét trạng thái hiện tại sẽ giúp bạn đưa ra lựa chọn đó.
Đó là lý do tại sao máy trạng thái là một giải pháp tốt.
Đây là một ví dụ :
class Attacking < State def play(warrior) warrior.attack! @player.set_state(Healing) unless enemy_found?(warrior) end end
Đây là một trong những trạng thái mà chiến binh của chúng ta có thể ở, khi chúng ta không có bất kỳ kẻ thù nào trong tầm mắt, chúng ta chuyển sang Healing
trạng thái phục hồi sau thiệt hại trong trận chiến.
Sử dụng Đá quý AASM
Nếu bạn muốn theo dõi trạng thái hiện tại trong khi đảm bảo rằng quá trình chuyển đổi là hợp lệ thì bạn có thể sử dụng đá quý máy trạng thái như AASM.
Đá quý này được xây dựng dựa trên ý tưởng về sự kiện (như nhấn công tắc đèn) để kích hoạt chuyển đổi sang các trạng thái khác.
Đây là một ví dụ :
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
Cách sử dụng lớp này :
light = Light.new p light.on? # true light.switch p light.on? # false
Sử dụng máy trạng thái này, bạn chỉ có thể chuyển sang trạng thái "bật" nếu trạng thái hiện tại là "tắt". Bạn cũng có thể có một số lệnh gọi lại (trước / sau) để chạy mã cụ thể trong quá trình chuyển đổi trạng thái.
Các lệnh gọi lại này có thể bao gồm những thứ như:
- Gửi email
- Ghi nhật ký thay đổi trạng thái
- Cập nhật trang tổng quan giám sát trực tiếp
Ngoài ra, AASM có tùy chọn để lưu trạng thái hiện tại vào cơ sở dữ liệu bằng cách sử dụng ActiveRecord
.
AASM Gem Video
Tóm tắt
Bạn đã học về máy trạng thái, mô hình thiết kế trạng thái và đá quý AASM! Hãy tiếp tục tìm hiểu ngay bây giờ bằng cách đăng ký nhận bản tin Ruby của tôi (hơn 7000 người đăng ký) để bạn không bỏ lỡ các bài viết mới và mẹo Ruby dành riêng cho người đăng ký .
Bây giờ là lúc thực hành với những ý tưởng mới này 🙂
Cảm ơn vì đã đọc!