[python|高級(jí)篇|筆記|設(shè)計(jì)模式|觀察者模式]
這兩天讀了[Head First設(shè)計(jì)模式][1]和[Python編程實(shí)戰(zhàn)][2]兩本書风喇,對(duì)設(shè)計(jì)模式終于有了那么一丟丟的體會(huì),在這里寫下來缕探,防止過兩天忘了魂莫。兩本一起讀的主要原因是因?yàn)槲覍?duì)java一竅不通。
HF里面對(duì)設(shè)計(jì)模式講的確實(shí)很通俗爹耗,按照他的說耙考,觀察者模式可以用報(bào)紙出版商和報(bào)紙訂閱者之間的關(guān)系來描述:
報(bào)社出版報(bào)紙谜喊,可以將它看做一個(gè)生產(chǎn)者,報(bào)紙訂閱者訂閱報(bào)紙倦始,可以將他看做一個(gè)個(gè)觀察者斗遏。
報(bào)社出版商可以提供以下的服務(wù):
- 注冊(cè)一個(gè)報(bào)紙訂閱者(Register)
- 注銷一個(gè)報(bào)紙訂閱者(Remove)
- 通知一個(gè)報(bào)紙訂閱者(Notify)
報(bào)紙訂閱者可以隨意定制自己,你是要拿報(bào)紙看楣号,還是鋪?zhàn)雷幼钜祝€是擦屁股隨你便
現(xiàn)在再來看觀察者模式的定義
定義了對(duì)象之間一對(duì)多依賴,當(dāng)一個(gè)對(duì)象改變狀態(tài)時(shí)炫狱,這個(gè)對(duì)象的所有依賴者都會(huì)收到通知并按照自己的方式進(jìn)行更新
按照HD上一個(gè)氣象站的例子來看觀察者模式
從氣象站取得數(shù)據(jù)后要在三個(gè)布告牌顯示這些數(shù)據(jù)藻懒,這三個(gè)布告牌顯示的內(nèi)容都不一樣,一塊實(shí)時(shí)顯示氣象數(shù)據(jù)视译,一塊顯示一段時(shí)間的統(tǒng)計(jì)數(shù)據(jù)嬉荆,一塊根據(jù)當(dāng)前數(shù)據(jù)顯示預(yù)測(cè)數(shù)據(jù),當(dāng)數(shù)據(jù)變化時(shí)酷含,這三個(gè)布告牌要按照自己的方式實(shí)時(shí)更新數(shù)據(jù)鄙早,例如,實(shí)時(shí)顯示布告牌就顯示當(dāng)前最新數(shù)據(jù)椅亚,統(tǒng)計(jì)數(shù)據(jù)布告牌將最大值最小值平均值顯示出來
先定義一個(gè)Observed類限番,這個(gè)類的作用類似于報(bào)紙出版商,他提供注冊(cè)呀舔,注銷弥虐,通知等功能
class Observed(object):
def __init__(self):
#此處初始化一個(gè)列表,里面裝滿了每一個(gè)觀察者
self.__observers = []
#注冊(cè)一個(gè)觀察者媚赖,注冊(cè)一個(gè)就往列表里添一個(gè)霜瘪,同時(shí)更新一下他的數(shù)據(jù)
def registerObservers(self, observer):
self.__observers.append(observer)
observer.update(self)
#注銷一個(gè)觀察者,誰不想看了惧磺,直接移走它颖对,以后數(shù)據(jù)更新了,跟他毛關(guān)系都沒了
def romoveObserver(self, observer):
self.__observers.remove(observer)
#通知每一個(gè)觀察者磨隘,數(shù)據(jù)更新了缤底,你們?nèi)グ褦?shù)據(jù)整理整理在布告牌上發(fā)布吧
def notifyObservers(self):
for observer in self.__observers:
observer.update(self)
定義一個(gè)WeatherModel類,這個(gè)類繼承字Observed類番捂,但是他提供采集數(shù)據(jù)的功能
#繼承了Observed類个唧,這樣它具有Observed類的數(shù)據(jù)及方法
class WeatherModel(Observed):
#初始化時(shí),加入一些初始數(shù)據(jù)
def __init__(self, temp, humidity, pressure):
super(WeatherModel, self).__init__()
self.temp = temp
self.humidity = humidity
self.pressure = pressure
#增加一個(gè)valueChanged方法白嘁,當(dāng)數(shù)據(jù)改變時(shí),更新當(dāng)前數(shù)據(jù)膘流,然后通知每一個(gè)觀察者數(shù)據(jù)變了絮缅,要更新了
def valueChanged(self, temp, humidity, pressure):
if self.temp != temp or \
self.humidity != humidity or \
self.pressure != pressure:
self.temp = temp
self.humidity = humidity
self.pressure = pressure
self.notifyObservers()
定義兩個(gè)觀察者類鲁沥,CurrentCondition和StatisticCondition
#這個(gè)布告板顯示實(shí)時(shí)的氣象數(shù)據(jù)
class CurrentCondition(object):
def __init__(self):
self.currData = []
#每一個(gè)觀察者都有一個(gè)update方法,Observed類里面的notifyObservers方法就是
#使用每個(gè)觀察者各自的update方法更新數(shù)據(jù)耕魄,這個(gè)布告板里面的update方法是將三個(gè)氣象參數(shù)打成元組然后
#放到初始化的currData列表里
def update(self, model):
self.currData.append((model.temp, model.humidity, model.pressure))
#這個(gè)布告板對(duì)氣象數(shù)據(jù)進(jìn)行統(tǒng)計(jì)
class StaticsCondition(object):
#初始化了三個(gè)列表画恰,分別存放溫度,濕度和壓力吸奴,這樣方便統(tǒng)計(jì)最大值允扇,最小值和平均值
def __init__(self):
self.statDataHumidity = []
self.statDataTemp = []
self.statDataPressure = []
#它的update方法是將每個(gè)參數(shù)放到各自的列表中去
def update(self, model):
self.statDataHumidity.append(model.humidity)
self.statDataTemp.append(model.temp)
self.statDataPressure.append(model.pressure)
之后,搞點(diǎn)數(shù)據(jù)測(cè)試一下
def main():
#先創(chuàng)建兩個(gè)觀察者實(shí)例
current = CurrentCondition()
statistic = StaticsCondition()
#創(chuàng)建一個(gè)模型實(shí)例则奥,傳入一些數(shù)
model = WeatherModel(20.0, 55.0, 1013.11)
#把這兩個(gè)觀察注冊(cè)一下考润,之后就可以給他們傳數(shù)據(jù)了
model.registerObservers(current)
model.registerObservers(statistic)
#整點(diǎn)數(shù)據(jù),這里只是隨便寫寫读处,用于測(cè)試
model.valueChanged(21.0, 52.3, 1013.12)
model.valueChanged(21.2, 53.3, 1013.12)
model.valueChanged(22.8, 56.1, 1013.18)
#輸出每個(gè)觀察的數(shù)據(jù)列表
print(current.currData)
print(statistic.statDataTemp)
print(statistic.statDataHumidity)
print(statistic.statDataPressure)
輸出的結(jié)果
#currData列表里面是每一次數(shù)據(jù)變化時(shí)糊治,三個(gè)參數(shù)的實(shí)時(shí)變化列表,可以取出后再布告牌上顯示罚舱,
#當(dāng)然需要在CurrentCondition()里實(shí)現(xiàn)display方法才可以顯示
[(20.0, 55.0, 1013.11), (21.0, 52.3, 1013.12), (21.2, 53.3, 1013.12), (22.8, 56.1, 1013.18)]
#三個(gè)列表分別存放溫度井辜,濕度,氣壓參數(shù)管闷,可以在display方法里面按照時(shí)間統(tǒng)計(jì)一下
#平均值粥脚,最大值,最小值顯示在布告牌上
[20.0, 21.0, 21.2, 22.8]
[55.0, 52.3, 53.3, 56.1]
[1013.11, 1013.12, 1013.12, 1013.18]
這就是觀察者模式包个,說白了就是模型和視圖沒有關(guān)系刷允,有點(diǎn)像MVC啊。
[1]: http://item.jd.com/10100236.html
[2]: http://item.jd.com/11518115.html