状态模型设计模式

3
我在实现模型状态时遇到了问题,这可能是由于错误的设计所致。
有一个具有状态的模型。该模型可以有多个实例,但只有几个预定义状态(如:已创建、已更新、已检索等)。对于每个单独的状态,都有一些计算逻辑用于该模型。例如,model.cost() 在每个状态下的计算方式都不同。
我希望ActiveRecord在保存模型时自动设置正确的model_status_id。我认为在理想情况下,我可以像这样做:
model.status = StatusModel.retrieved

并且

case status
  when renewed
    # ...
  when retrieved
    # ..
end

我认为需要将状态保存在数据库中的模型行中,以下是我的代码:

ModelStatus < ActiveRecord::Base
  has_many :models
Model < ActiveRecord::Base
  belongs_to :model_status

然而,这在代码中给了我很多问题。有没有人对此有好的想法或模式?

如果状态是预定义的,将其作为代码中的常量而不是存储在数据库中,这样不就足够了吗? - Olly
3个回答

2
您所描述的情况似乎适合使用状态机。有许多Ruby状态机的实现,您可以在ruby-toolbox网站上看到一个相当代表性的列表。
在定义状态机时,您可以定义几个状态和转换。每个转换将您的模型从一个状态转移到另一个状态,并沿途执行一些代码。通常其DSL非常好用。
您的示例可能如下所示:
model.retrieve!

这将把模式状态从任何状态更改为已检索,如果当前状态无法转换为已检索,则会引发异常。


1
为什么不将实际模型的状态部分保留下来呢?如果它们是预定义的,那就不需要太多工作了。
class Model < ActiveRecord::Base

  STAT_CREATED   = 1 
  STAT_RENEWED   = 2
  STAT_RETRIEVED = 4

  validates_inclusion_of :status,
                         :in => [1, 2, 4]


  def created?
    status & STAT_CREATED
  end

  def renewed?
    status & STAT_RENEWED
  end

  def retrieved?
    status & STAT_RETRIEVED
  end

end

这样,您可以直接测试模型实例(例如,如果@model.created?),或者像这样编写您的case语句:

case @model.status
when Model::STAT_CREATED
...
when Model::STAT_RENEWED
...

非常感谢!看起来很合乎逻辑。有时候我想得太复杂了。 - benvds

1

还可以尝试查看acts_as_state_machine插件。我最近在一个项目中使用它,效果很好。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接