强大的有限状态机 - state_machine

在推荐Ruby on Rails给做企业应用的朋友时候,比较常见的问题有"Ruby有没有好用的开源工作流引擎?",基于有限状态机([url=http://en.wikipedia.org/wiki/Finite_state_machine]Finite State Machine - FSM[/url])构建工作流引擎是经常使用的实现方法,写篇短文介绍一下Ruby世界里的有限状态机:

首先列几个开源的Ruby FSM项目:
[list]
[*][url=http://github.com/pluginaweek/state_machine]state_machine[/url]
[*][url=http://github.com/rubyist/aasm]act_as_state_machine[/url]
[*][url=http://github.com/ryan-allen/workflow]Ryan Allen's workflow[/url]
[*][url=http://github.com/avdi/alter-ego]Alter Ego[/url]
[/list]
其中第一个项目state_machine是作者经过[url=http://www.pluginaweek.org/2009/03/08/state_machine-one-machine-to-rule-them-all/]2年半时间[/url]陆续开发的,特性比较完整,而且最近开发也比较活跃,下面简单介绍一下它的强大功能:
[list]
[*]可以在任意的Ruby类里面定义多个状态机
[*]基于属性的event transitions
[*]提供了和ActiveRecord / DataMapper / Sequel等多个ORM的集成
[*]提供了before/after transition hook以方便于集成
[*]状态驱动的instance/class行为
[*]基于GraphViz的创建状态机图片
[*]...
[/list]

[size=large]1. 基础用法:[/size]
我们来看一下它提供的一个红绿灯的例子
[img]/upload/attachment/117418/015ce22e-ac1d-3029-b774-5b6ca13dd4fb.png[/img]

得益于Ruby语言的优秀特性,state_machine定义了一套简洁DSL,使得代码非常易懂/易维护:

class TrafficLight
state_machine :initial => :stop do #定义初始状态为stop
event :cycle do #定义cycle事件,让状态从stop到proceed到caution到stop进行改变
transition :stop => :proceed, :proceed => :caution, :caution => :stop
end
end
end


使用这个红绿灯的代码:

light = TrafficLight.new
p light.state
6.times do
light.cycle
p light.state
end


[size=large]2. transition hook:[/size]
利用state_machine提供的before/after transition hook机制,我们可以简洁地实现很多需求,比如订单状态改变的时候,我们需要记录一下:

class Order
state_machine :initial => :pending
before_transition :log_state_change
#...
end

def log_state_change(transition)
event, from, to = transition.event, transition.from_name, transition.to_name
puts("Order #{number}: #{from} => #{to} on #{event}")
end
end


也可以有选择性地在某些关键状态改变时做些动作:

after_transition :pending => :completed, :pending => :closed do
#send email to order owner
end


[size=large]3. 和ORM集成:[/size]
和Rails的ActiveRecord集成是很简单的一件事情,简单到你什么都不需要做,直接在Model文件里面定义就可以了:

class Order < ActiveRecord::Base
state_machine :initial => :pending do
event :confirm do
#...
end
end
end


然后在数据库里面添加一个栏位叫state,这样就可以持久化了:

order = Order.create(...)
p order.state # pending


结合它默认设置的scope,我们就可以写出这样简洁而又符合自然语法的代码:

#找出所有状态为pending的订单,一一进行确认
Order.with_state(:pending).all.each{|order| order.confirm}


和DataMapper / Sequel集成也是很简单,都是直接在Model文件里面定义,然后数据库添加栏位,而不需要额外的工作。

简单介绍到此,state_machine还有更多强大的功能不是这篇短文能够覆盖的,大家有兴趣的可以看它的文档和源代码。

最后值得提一下的是,这个项目总共只有1200行不到的代码,和动辄超过万行的Java workflow engine相比,学习起来是很轻松愉快的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值