一个python程序员的ruby三日游(四)——观察者模式

时间:2022-05-31 11:49:30

设计模式算是在OO中比较有趣的东西,特别是对于如我之类的用得不是很多的,虽然有时候也会用上,但是并不知道用的是怎样的模式。之前了解了几天的设计模式,实际上也就是将平常经常用到的一些东西进行了总结,如此而已,学习设计模式的另外一个重要的意义在于,我们使用了设计模式的时候我们会知道自己使用了,并且还会知道用了是怎样的设计模式。

至于设计模式这个东西和有些东西一样,是发现的而不是发明的,换句话说,我们可以将经常合到一起的几种模式用一个新的模式来命名,它是复合模式,但是也可以用别的模式来命名。(转载保留 Phodal's Blog Phodal's  zenthink

设计模式算是简化了我们在面向对象设计时候的诸多不足,这个在系统设计的初期有时候会有一定的作用,不过多数时候对于我来说,会用上他的时候,多半是在重构的时候,因为不是很熟悉。

观察者模式

观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

一个软件系统常常要求在某一个对象的状态发生变化的时候,某些其它的对象做出相应的改变。做到这一点的设计方案有很多,但是为了使系统能够易于复用,应该选择低耦合度的设计方案。减少对象之间的耦合有利于系统的复用,但是同时设计师需要使这些低耦合度的对象之间能够维持行动的协调一致,保证高度的协作(Collaboration)。观察者模式是满足这一要求的各种设计方案中最重要的一种。


简单的来说,就是当我们监测到一个元素变化的时候,另外的元素依照此而改变。



Ruby观察者模式

Ruby中为实现Observer模式提供了名为observer的库,observer库提供了Observer模块。

API如下所示

方法名

功 能

add_observer(observer)

添加观察者

delete_observer(observer)

删除特定观察者

delete_observer

删除观察者

count_observer

观察者的数目

change(state=true)

设置更新标志为真

changed?

检查更新标志

notify_observer(*arg)

通知更新,如果更新标志为真,调用观察者带参数arg的方法


Ruby观察者简单示例

这里要做的就是获取一个json数据,将这个数据更新出来。


获取json数据,同时解析。

require 'net/http'
require 'rubygems'
require 'json'

class GetData
attr_reader:res,:parsed

def initialize(uri)
uri=URI(uri)
@res=Net::HTTP.get(uri)
@parsed=JSON.parse(res)
end

def id
@parsed[0]["id"]
end

def sensors1
@parsed[0]["sensors1"].round(2)
end

def sensors2
@parsed[0]["sensors2"].round(2)
end

def temperature
@parsed[0]["temperature"].round(2)
end

def led1
@parsed[0]["led1"]
end

end

下面这个也就是重点,和观察者相关的,就是被观察者,由这个获取数据。

通过changed ,同时用notify_observer方法告诉观察者

require 'rubygems'
require 'thread'
require 'observer'
require 'getdata'
require 'ledstatus'

class Led
include Observable

attr_reader:data
def initialize
@uri='http://www.xianuniversity.com/athome/1'
end
def getdata
loop do
changed()
data=GetData.new(@uri)
changed
notify_observers(data.id,data.sensors1,data.sensors2,data.temperature,data.led1)
sleep 1
end
end
end

然后让我们新建一个观察者

class LedStatus
def update(arg,sensors1,sensors2,temperature,led1)
puts "id:#{arg},sensors1:#{sensors1},sensors2:#{sensors2},temperature:#{temperature},led1:#{led1}"
end
end

测试

require 'spec_helper'

describe LedStatus do
let(:ledstatus){LedStatus.new()}

describe "Observable" do
it "Should have a result" do
led=Led.new
led.add_observer(ledstatus)
led.getdata
end
end

end

测试结果如下所示

phodal@linux-dlkp:~/tw/observer> rake
/usr/bin/ruby1.9 -S rspec ./spec/getdata_spec.rb ./spec/ledstatus_spec.rb
id:1,sensors1:22.0,sensors2:11.0,temperature:10.0,led1:0
id:1,sensors1:22.0,sensors2:11.0,temperature:10.0,led1:1
id:1,sensors1:22.0,sensors2:11.0,temperature:10.0,led1:0
id:1,sensors1:22.0,sensors2:11.0,temperature:10.0,led1:1
id:1,sensors1:22.0,sensors2:11.0,temperature:10.0,led1:1
id:1,sensors1:22.0,sensors2:11.0,temperature:10.0,led1:1
 

总结

使用Ruby自带的Observer库的优点是,让我们可以简化相互之间的依赖性。同时,也能简化程序的结构,相比于自己写observer的情况下。