模块 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+ 一起使用。
以下示例说明了 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
常量
- VERSION
公共实例方法
将 observer
添加为此对象的观察者。以便它将接收通知。
observer
-
将接收更改通知的对象。
func
-
符号,命名当此
Observable
发生更改时将被调用的方法。此方法必须为
observer.respond_to?
返回 true,并且当调用notify_observers
时将接收*arg
,其中*arg
是此Observable
传递给notify_observers
的值。
# File observer-0.1.2/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
时,才会发送通知。
state
-
布尔值,指示此
Observable
的更改状态。
# File observer-0.1.2/lib/observer.rb, line 194 def changed(state=true) @observer_state = state end
如果自上次 notify_observers
调用以来此对象的状态已更改,则返回 true。
# File observer-0.1.2/lib/observer.rb, line 202 def changed? if defined? @observer_state and @observer_state true else false end end
返回与此对象关联的观察者的数量。
# File observer-0.1.2/lib/observer.rb, line 180 def count_observers if defined? @observer_peers @observer_peers.size else 0 end end
从此对象中删除 observer
作为观察者,以便它不再接收通知。
observer
-
此
Observable
的观察者
# File observer-0.1.2/lib/observer.rb, line 166 def delete_observer(observer) @observer_peers.delete observer if defined? @observer_peers end
删除与此对象关联的所有观察者。
# File observer-0.1.2/lib/observer.rb, line 173 def delete_observers @observer_peers.clear if defined? @observer_peers end
如果此对象的更改状态为 true
,则通知观察者状态发生更改。
这将调用 add_observer
中命名的方法,并传递 *arg
。然后将更改状态设置为 false
。
*arg
-
传递给观察者的任何参数。
# File observer-0.1.2/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