模块 Observable
观察者模式(也称为发布/订阅)提供了一种简单的机制,让一个对象可以在其状态发生变化时通知一组感兴趣的第三方对象。
机制¶ ↑
通知类混合了 Observable
模块,该模块提供了管理关联观察者对象的 方法。
可观察对象必须
-
断言它具有
#changed
-
调用
#notify_observers
观察者使用 Observable#add_observer
订阅更新,这也会指定通过 notify_observers
调用的方法。 notify_observers
的默认方法是 update。
示例¶ ↑
以下示例很好地演示了这一点。一个 Ticker
在运行时会不断接收其 @symbol
的股票 Price
。一个 Warner
是价格的通用观察者,演示了两个观察者,一个 WarnLow
和一个 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
与 proc 的使用¶ ↑
#notify_observers
方法也可以通过使用 :call
作为 func
参数与 +proc+s 一起使用。
以下示例说明了 lambda 的使用
require 'observer' class Ticker include Observable def run # logic to retrieve the price (here 77.0) changed notify_observers(77.0) end end ticker = Ticker.new warner = ->(price) { puts "New price received: #{price}" } ticker.add_observer(warner, :call) ticker.run
常量
- 版本
公共实例方法
将 observer
添加为该对象的观察者。这样它就会收到通知。
观察者
-
将收到更改通知的对象。
函数
-
Symbol
,命名将在该Observable
发生更改时调用的方法。此方法必须对
observer.respond_to?
返回 true,并且将在调用notify_observers
时接收*arg
,其中*arg
是由该Observable
传递给notify_observers
的值。
# File lib/observer.rb, line 153 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
设置该对象的更改状态。只有当更改的 state
为 true
时才会发送通知。
状态
-
布尔值,指示该
Observable
的更改状态。
# File lib/observer.rb, line 194 def changed(state=true) @observer_state = state end
如果该对象的状态自上次调用 notify_observers
以来已更改,则返回 true。
# File lib/observer.rb, line 202 def changed? if defined? @observer_state and @observer_state true else false end end
返回与该对象关联的观察者数量。
# File lib/observer.rb, line 180 def count_observers if defined? @observer_peers @observer_peers.size else 0 end end
从该对象中删除 observer
作为观察者,使其不再接收通知。
观察者
-
该
Observable
的观察者
# File lib/observer.rb, line 166 def delete_observer(observer) @observer_peers.delete observer if defined? @observer_peers end
删除与该对象关联的所有观察者。
# File lib/observer.rb, line 173 def delete_observers @observer_peers.clear if defined? @observer_peers end
如果该对象的更改状态为 true
,则通知观察者状态更改。
这将调用在 add_observer
中命名的方法,并传递 *arg
。然后将更改状态设置为 false
。
*arg
-
要传递给观察者的任何参数。
# File lib/observer.rb, line 218 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