我有一个有两个状态的类,“state1”和“state2”(可能只有两个状态,并且它自创建实例以来从未改变)并且跟随代码
class MyClass
attr_accessor :myvar1, :myvar2, :state
include Extension1
include Extension2
def func1
send("#{self.state}_func1")
end
def otherfunc
send("#{self.state}_otherfunc")
end
def anotherfunc
send("#{self.state}_anotherfunc")
end
end
module Extension1 #handles state1 functions
def state1_func1
#do something using MyClass instance vars
end
def state1_otherfunc
#do something using MyClass instance vars
end
def state1_anotherfunc
#do something using MyClass instance vars
end
end
module Extension2 #handles state2 functions
def state2_func1
#do something using MyClass instance vars
end
def state2_otherfunc
#do something using MyClass instance vars
end
def state2_anotherfunc
#do something using MyClass instance vars
end
end
如何改进此代码? (这个例子非常基本,实际对象同时有两个状态属性,我需要根据第二个状态覆盖第一个状态的state_machine事件)
答案 0 :(得分:1)
Ruby有很多方法可以做你需要做的事情。按照你选择的路径,我就是这样做的,Pavle:
module Ext1
def f_state_a
puts "state a action"
end
end
module Ext2
def f_state_b
puts "state b action"
end
end
class X
include Ext1, Ext2
attr_reader :state
def initialize( state=:a )
@state = state
end
def f
case state
when :a then f_state_a
when :b then f_state_b
end
end
end
a, b = [ :a, :b ].map &X.method( :new )
a.f # ...
b.f # ...
答案 1 :(得分:1)
您正在寻找的是state pattern的实现,我认为,在Ruby中实现它的最好方法是通过Forwardable
模块,避免显式元编程。提出这个想法的一个简单例子:
require 'forwardable'
class MyClass
extend Forwardable
def_delegators :@state, :func1
def initialize
@state = InitialState.new
end
def do_transition
@state = FinalState.new
end
end
class InitialState
def func1; "InitialState" end
end
class FinalState
def func1; "FinalState" end
end
obj = MyClass.new
obj.func1
# => "InitialState"
obj.do_transition
obj.func1
# => "FinalState"
更新:由于MyClass
个对象是使用状态初始化的,并且它永远不会更改,可能它们实际上是strategies,您可以像这样修改MyClass
:
class MyClass
extend Forwardable
def_delegators :@strategy, :func1
def initialize(strategy)
@strategy = strategy
end
end
答案 2 :(得分:0)
为了回应toro2k的评论,我可以自由地展示我在家里做的事情,例如:
module Ext1
def f
puts "state a action"
end
end
module Ext2
def f
puts "state b action"
end
end
class X
attr_reader :state
def initialize( state=:a )
@state = state
extend case state
when :a then Ext1
when :b then Ext2
end
end
end
a, b = [ :a, :b ].map &X.method( :new )
a.f # ...
b.f # ...
但这与帕维尔在他的问题中所提出的思路完全不同。
注意: Pavel的实例“状态”永远不会改变,因此没有转换。如果它们之间存在多个状态和转换,那么您将拥有一个位置/转换网络,也就是说。 Petri网 sensu lato ,嵌入在实例中。这将由我的y_petri
gem处理,其中place和transition本身就是对象,属于Net
对象,它是MyClass
实例的属性,并且其状态向量将以类似于您或Pavel建议的方式控制其行为。另一个可以考虑的宝石是state machine
宝石。