Giới thiệu về Gem State Machine

Giới thiệu State Machine

State Machine giúp đỡ một đối tượng có thể kiểm soát được các trạng thái (state) của mình, khi di chuyển các trạng thái trạng với nhau. Mỗi khi có một sự kiện diễn ra đối tượng sẽ di chuyển từ trạng thái này sang trạng thái khác.

Ở hình bên trên trạng thái đầu tiên là State A.Với sự kiện T1 diễn ra, trạng thái State A sẽ di chuyển đến trạng thái State B v.v…

vì sao nên dùng State Machine?
State Machine giúp đỡ ta mô tả hành vi của một đối tượng một cách dễ hiểu và có tác dụng. Khi chuyển tiếp trạng thái, tạo trình kích hoạt hoặc có các sự kiện đối tượng đều phải xác định trạng thái cấp quyền thì mới được thực hiện.
Dùng State Machine sẽ quản lý được tất cả các dữ kiện lưu chuyển của flow bằng một machine duy nhất. (với mỗi flow là 1 even)

Cài đặt

Thêm gem vào Gemfile của app của bạn:

gem ‘state_machine’
gem ‘ruby-graphviz’, :require => ‘graphviz’

Và tiếp nữa thực hiện:

$ bundle

Hoặc tự cài đặt bằng:

$ gem install state_machines

Tạo Model

$ rails generate model name_model state:string
rake db:migrate

Ví dụ:

ta sẽ tạo model cho một cuộc gọi cho app điện thoại. Một cuộc gọi sẽ có trạng thái có trả lời hay không. Trước hết ta sẽ dùng boolean answered để trả về kết quả trạng thái.

class PhoneCall     attr_accessor :answered      def initialize         self.answered = false     end end 

Cách xử lý tình thế không trả lời được hoặc cuộc gọi bị lỗi

class PhoneCall     attr_reader :answered, :failed, :failure_reason      def initialize         @answered = false         @failed = false     end      def answer         @answered = true     end      def fail(reason)         @failed = true         @failure_reason = reason     end end 

Nhưng khi ta muốn theo dõi xem cuộc gọi đang quay số hay đâng trong cuộc tiếp chuyện hay muốn biết thời gian cuộc tiếp chuyện, …. Khi đó chúng cần được hiểu thêm các phương thức với mỗi phương thức lại cần phải thêm các phương thức kiểm tra cho các boolean khác nhau.
Model PhoneCall sẽ trở lên rất phức tạp khi ta thêm nhiều thuộc tính và trạng thái.
Thay thế với State Machine
Ở mỗi một lúc PhoneCall sẽ có trạng thái khác nhau:

dialing in_progress completed failed
Quy định sự đổi khác trạng thái: dialing -> in_progress or failed in_progress -> completed
Phần xử lý với mỗi bối cảnh: failure_reason thông tin lỗi nếu cuộc gọi fail duration tính thời gian nếu cuộc gọi thành công
Tất cả các hành vi của PhoneCall đều thể rất dễ mô tả bằng cách dùng một state_machine thay vì quản lý thủ công nhiều booleans và flags:

# Using the state_machine gem. class PhoneCall     state_machine :state, :initial => :dialing do         event :answered do             transition :dialing => :in_progress         end          event :failure do             transition :dialing => :failed         end          event :hangup do             transition :in_progress => :completed         end          state :completed do             def duration                 @end_time - @start_time             end         end          state :failed do             attr_accessor :failure_reason         end          before_transition :dialing => :in_progress, :do => :rec_start_time         after_transition :in_progress => :completed, :do => :rec_end_time     end      def answered?         in_progress? || completed?     end      private      def rec_start_time         @start_time = Time.now     end      def rec_end_time         @end_time = Time.now     end end 

Nguồn viblo.asia