问题很简单.对象需要通知观察者可能感兴趣的一些事件.
当我坐下来验证我现在在Ruby中编写的设计只是为了验证它.我发现自己难以理解如何实现对象事件.在.Net中,这将是一个单行程.. .Net也可以执行处理程序方法签名验证等.例如
// Object with events public delegate void HandlerSignature(int a); public event HandlerSignature MyEvent; public event HandlerSignature AnotherCriticalEvent; // Client MyObject.MyEvent += new HandlerSignature(MyHandlerMethod); // MyHandlerMethod has same signature as delegate
是否有一个EventDispatcher模块或者我缺少的东西,我可以绑定到Ruby类?希望得到一个符合Ruby最少惊喜原则的答案. 事件将是事件的名称加上在事件发生时需要调用的[observer,methodName]对象的队列.
首先,在Ruby中没有方法签名.最接近的是检查函数的arity.鸭子打字需要不同的思考(略).
可观察到的模块是一个开始,但如果你有一个要求,有从单一类中的多个事件,它可能是不够的.
这是一个快速草图.它支持方法和块.根据需要进行修改以适应您的代码,线程方法等.例如,您可以使用method_missing在方法名称中包含事件名称,而不是将其作为参数.
class EventBase def initialize @listeners = Hash.new end def listen_event(name, *func, &p) if p (@listeners[name] ||= Array.new) << p else (@listeners[name] ||= Array.new) << func[0] end end def ignore_event(name, func) return if !@listeners.has_key?(name) @listeners[name].delete_if { |o| o == func } end def trigger_event(name, *args) return if !@listeners.has_key?(name) @listeners[name].each { |f| f.call(*args) } end end class MyClass < EventBase def raise_event1(*args) trigger_event(:event1, *args) end def raise_event2(*args) trigger_event(:event2, *args) end end class TestListener def initialize(source) source.listen_event(:event1, method(:event1_arrival)) source.listen_event(:event2) do |*a| puts "event 2 arrival, args #{a}" end end def event1_arrival(*a) puts "Event 1 arrived, args #{a}" end end s = MyClass.new l = TestListener.new(s) s.raise_event1("here is event 1") s.raise_event2("here is event 2")
为什么不写自己的事件类?就像是
class Event def initialize @handlers = Array.new end def fire @handlers.each do |v| v.call end end def << handler @handlers << handler end end e = Event.new e << lambda { puts "hello" } e << lambda { puts "test" } e.fire
这只是一个最小的样本,但可以以任何方式扩展.在.Net中添加像sender和eventArgs这样的参数,或者你喜欢的任何东西;-)