Ruby 2.4

Observable

module Observable

观察者模式(也称为发布/订阅)为一个对象提供了一种简单的机制,用于在状态发生变化时通知一组感兴趣的第三方对象。

机制

通知类混入Observable模块中,该模块提供了管理关联观察器对象的方法。

可观察对象必须:

  • 断言它有 #changed

  • 调用 #notify_observers

观察者使用#add_observer订阅更新,它还指定通过notify_observers调用的方法。notify_observers的默认方法是更新。

下面的例子很好地证明了这一点。一Ticker,在运行时,不断地接收股票Price为它@symbol。A Warner是价格的一般观察者,并且两个警告者被证明是a WarnLow和a WarnHigh,如果价格低于或高于他们设定的限制,它们分别发出警告。

update回调使华纳而不被显式调用运行。该系统由Ticker几名观察员组成,观察员在没有顶级代码干扰的情况下尽自己的职责。

请注意,发布者和订阅者(​​观察者和观察者)之间的合同未被声明或执行。在Ticker发布时间和价格,以及华纳接收。但如果你不确保你的合同是正确的,没有别的可以警告你。

require "observer" class Ticker ### Periodically fetch a stock price. include Observable def initialize(symbol) @symbol = symbol end def run last_price = nil loop do price = Price.fetch(@symbol) print "Current price: #{price}\n" if price != last_price changed # notify observers last_price = price notify_observers(Time.now, price) end sleep 1 end end end class Price ### A mock class to fetch a stock price (60 - 140). def self.fetch(symbol) 60 + rand(80) end end class Warner ### An abstract observer of Ticker objects. def initialize(ticker, limit) @limit = limit ticker.add_observer(self) end end class WarnLow < Warner def update(time, price) # callback for observer if price < @limit print "--- #{time.to_s}: Price below #@limit: #{price}\n" end end end class WarnHigh < Warner def update(time, price) # callback for observer if price > @limit print "+++ #{time.to_s}: Price above #@limit: #{price}\n" end end end ticker = Ticker.new("MSFT") WarnLow.new(ticker, 80) WarnHigh.new(ticker, 120) ticker.run

生产:

Current price: 83 Current price: 75 --- Sun Jun 09 00:10:25 CDT 2002: Price below 80: 75 Current price: 90 Current price: 134 +++ Sun Jun 09 00:10:25 CDT 2002: Price above 120: 134 Current price: 134 Current price: 112 Current price: 79 --- Sun Jun 09 00:10:25 CDT 2002: Price below 80: 79

公共实例方法

add_observer(observer, func=:update) Show source

observer作为观察者添加到此对象上。以便它会收到通知。

observer

将被通知更改的对象。

func

符号命名当Observable发生更改时将要调用的方法。

此方法必须返回true observer.respond_to?并且将*arg在notify_observers被调用时接收,其中*arg值是由此Observable传递给notify_observers的值

# File lib/observer.rb, line 127 def add_observer(observer, func=:update) @observer_peers = {} unless defined? @observer_peers unless observer.respond_to? func raise NoMethodError, "observer does not respond to `#{func}'" end @observer_peers[observer] = func end

changed(state=true) Show source

设置此对象的更改状态。只有当改变的通知将被发送statetrue

state

布尔值,指示此Observable的状态已更改。

# File lib/observer.rb, line 168 def changed(state=true) @observer_state = state end

changed?() Show source

如果自上次notify_observers调用后更改了此对象的状态,则返回true。

# File lib/observer.rb, line 176 def changed? if defined? @observer_state and @observer_state true else false end end

count_observers() Show source

返回与此对象关联的观察者的数量。

# File lib/observer.rb, line 154 def count_observers if defined? @observer_peers @observer_peers.size else 0 end end

delete_observer(observer) Show source

observer作为观察者移除此对象,以便它不再接收通知。

observer

这个Observable的观察者

# File lib/observer.rb, line 140 def delete_observer(observer) @observer_peers.delete observer if defined? @observer_peers end

delete_observers() Show source

删除与此对象关联的所有观察者。

# File lib/observer.rb, line 147 def delete_observers @observer_peers.clear if defined? @observer_peers end

notify_observers(*arg) Show source

如果该对象的状态改变,通知观察者状态改变true

这将调用add_observer中传递的方法*arg。然后将更改的状态设置为false

*arg

任何传递给观察者的参数。

# File lib/observer.rb, line 192 def notify_observers(*arg) if defined? @observer_state and @observer_state if defined? @observer_peers @observer_peers.each do |k, v| k.send v, *arg end end @observer_state = false end end