问题很简单.对象需要通知观察者可能感兴趣的一些事件.
当我坐下来验证我现在在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
Run Code Online (Sandbox Code Playgroud)
是否有一个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")
Run Code Online (Sandbox Code Playgroud)
小智 6
为什么不写自己的事件类?就像是
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
Run Code Online (Sandbox Code Playgroud)
这只是一个最小的样本,但可以以任何方式扩展.在.Net中添加像sender和eventArgs这样的参数,或者你喜欢的任何东西;-)