2008-10-29 24 views
11

Vấn đề rất đơn giản. Một đối tượng cần phải thông báo cho một số sự kiện mà các nhà quan sát có thể quan tâm.Tương đương với các sự kiện .NET trong Ruby là gì?

Khi tôi ngồi xác thực một thiết kế mà tôi đã nấu ngay bây giờ trong Ruby chỉ để xác nhận nó .. Tôi thấy mình bị bối rối như thế nào để thực hiện các sự kiện đối tượng. Trong. Net này sẽ là một lớp lót .. Net cũng có phương pháp xử lý chữ ký xử lý, vv. ví dụ.

// 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 

Có mô-đun EventDispatcher hoặc thứ gì đó mà tôi thiếu mà tôi có thể đeo vào lớp Ruby không? Hy vọng cho một câu trả lời phù hợp với nguyên tắc của Ruby ít ngạc nhiên nhất. Sự kiện sẽ là tên của sự kiện cộng với hàng đợi của các đối tượng [observer, methodName] cần được gọi khi sự kiện diễn ra.

Trả lời

2
+1

Không hẳn .. Điều này có vẻ là việc triển khai Mẫu thiết kế quan sát. Những gì tôi cần là cho đối tượng lò hơi để lộ nhiều sự kiện như WaterExhausted, Started, vv và khách hàng đăng ký với các trình xử lý của họ (không bị ràng buộc với một phương thức 'cập nhật') – Gishu

8

Thứ nhất, trong Ruby không có chữ ký phương thức. Việc gần nhất sẽ kiểm tra tính chất của hàm. Cách gõ vịt yêu cầu suy nghĩ khác nhau (hơi).

Mô-đun có thể quan sát là bắt đầu, nhưng nếu bạn có yêu cầu có nhiều sự kiện từ một lớp thì có thể không đủ.

Đây là bản phác thảo nhanh. Nó hỗ trợ các phương thức và khối. Sửa đổi khi cần thiết để thích ứng với mã của bạn, cách tiếp cận luồng, v.v. Ví dụ: bạn có thể sử dụng method_missing để có tên sự kiện trong tên phương thức chứ không phải là tham số.

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 [email protected]_key?(name) 
     @listeners[name].delete_if { |o| o == func } 
    end 

    def trigger_event(name, *args) 
     return if [email protected]_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") 
2

Tôi muốn nói rằng không có sự tương tự ở mức ngôn ngữ trong các sự kiện từ Ruby đến .NET. Cách mà đường ray giao dịch với nó là với ActiveSupport::Callbacks (có một ví dụ trên trang đó).

+0

Có lẽ vì Ruby là ngôn ngữ chứ không phải khung? –

+0

nếu tôi hiểu điều này..Callbacks như trong Rails là giống như móc .. nơi bạn có để lấy được từ một lớp để plug-in hành vi tại một điểm nhất định. không hoàn toàn là sự kiện .. mà không vài 'người quan sát' và 'có thể quan sát' – Gishu

6

Tại sao bạn không viết lớp sự kiện của riêng mình? Một cái gì đó như

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 

Đây chỉ là mẫu tối thiểu, nhưng có thể được gia hạn bằng mọi cách. Thêm thông số như người gửi và eventArgs vào .Net hoặc bất kỳ thứ gì bạn thích ;-)

0

Tôi đã viết đá quý chỉ vì điều này vì tôi đã có cùng một vấn đề. Hãy thử điều này:

gem install ruby_events 

Làm theo hướng dẫn như trên http://github.com/nathankleyn/ruby_events, nhưng trong một nutshell:

require 'rubygems' 
require 'ruby_events' 

class Example 
    def initialize 
    events.listen(:test_event) do |event_data| 
     puts 'Hai there!' 
     puts event_data 
    end 
    end 

    def call_me 
    events.fire(:test_event, 'My name is Mr Test Man!') 
    end 
end 

e = Example.new 
e.call_me # Fires the event, and our handler gets called! 
0

Một lưu ý nhanh chóng về vấn đề này. Tôi đề nghị bạn nhìn vào EventMachine

Đây là một khác nhau tìm một ý tưởng tương tự. Nó thực hiện một mô hình hướng sự kiện để bạn ở một mức tương đương với các sự kiện .Net và xem xét mô-đun EventMachine là trình xử lý sự kiện CLR.

Cũng lùi lại một bước, Ruby theo một mô hình xử lý Smalltalk trong đó bất kỳ cuộc gọi nào đến phương thức là một thông báo (như là một sự kiện) được gửi đến đối tượng (xem phương thức Send()). EventMachine cung cấp cho bạn là một lát đơn luồng trên các sự kiện.Bạn có thể sử dụng một cái gì đó như Rack để xử lý các chủ đề hoặc công nhân.

1

Hãy xem qua các số ruby state machine libraries khác nhau. Họ có ý định giải quyết một vấn đề lớn hơn là các sự kiện, nhưng có thể cung cấp cho bạn một giải pháp.

Tôi đã sử dụng đá quý state_machine với thành công, bao gồm events.

0

Tôi là một noob nhưng Ruby có vẻ thực sự mạnh mẽ. Bạn có thể tự mình thực hiện các sự kiện kiểu C# như sau:

module Observable 
    class Event 
     def initialize 
      @to_call = [] 
     end 
     def fire(*arguments) 
      @to_call.each { |proc| proc.call(*arguments) } 
     end 
     def call(proc) 
      @to_call << proc 
     end 
     def dont_call(proc) 
      @to_call.delete proc 
     end 
    end 
    def self.append_features(cls) 
     def cls.event(sym) 
      define_method(sym.to_s) do 
       variable_name = "@#{sym}" 
       if not instance_variable_defined? variable_name then 
        instance_variable_set variable_name, Event.new 
       end 
       instance_variable_get variable_name 
      end 
     end 
    end 
end 

# Example 

class Actor 
    include Observable 
    event :whenActed 
    def act 
     whenActed.fire("Johnny") # fire event whenActed with parameter Johnny 
    end 
end 

actor = Actor.new 

def apploud(whom) 
    print "Bravo #{whom}!\n" 
end 

applouder = method(:apploud) 

actor.whenActed.call applouder 

actor.act 
0

Tôi đã tạo một đá quý làm chính xác những gì bạn muốn và đáng ngạc nhiên gọi là event_dispatcher như bạn đã đề cập. Tôi hy vọng nó sẽ giúp một ai đó: event_dispatcher

Các vấn đề liên quan