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
设置此对象的更改状态。只有当改变的通知将被发送state
的true
。
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