Head First 设计模式——观察者模式(Observer Pattern)——Python实现(2)
本作品采用知识共享署名-非商业性使用-相同方式共享 3.0 Unported许可协议进行许可。允许非商业转载,但应注明作者及出处。作者:liuyuan_jq
2011-06-14
上节的例子中有两个缺点:
1. 上个例子中我们采用的是推的方式,当主题对象的数据更新时,所有的观察者对象的数据都必须更新。但是主题对象传递给观察者的数据可能不是某些观察者想要的或者观察者只是使用其中一部分数据。在这种情况下,观察者对象会强迫收到一些无用的数据。
2. 当主题对象的数据更新时,所有的观察者对象都必须立即更新。气象站测试非常敏锐,以至于温度计读数每十分之一度都会更新,这会造成WeatherData对象持续不断地通知观察者,我们并不希望看到这样的事情发生。如果我们希望半度以上才更新,就可以在温度差距到达半度时,调用setChanged(),进行有效的更新。
解决方案:
1. 如果观察者对象经常收到一些无用的信息,则可以采用拉的方式,主动地从主题对象获得消息。主题对象可以提供一些getter方法来满足要求。
2. 可以增加一个setChanged()方法,用来标记主题对象状态已经改变的事实,让notifyObservers()知道当它被调用时应该更新观察者。如果调用notifyObservers()之前没有先调用setChanged(),则观察者就不会被通知。你也许不会用到此功能,但是添加这样的功能,当需要时就可以使用,让你的系统可以更有弹性。
源码
weatherData.py
#!/usr/bin/env python# -*- coding:utf-8 -*-from subject import Subjectclass WeatherData(Subject):"""天气数据类,是一个主题类"""# 类静态成员observers = []changed = Falsedef __init__(self):self.temperature = 0.0self.humidity = 0.0self.pressure = 0.0def registerObserver(self, observer):"""注册观察者对象"""self.observers.append(observer)def removeObserver(self, observer):"""注销观察者对象"""self.observers.remove(observer)def notifyObservers(self):"""通知所有的观察者对象"""if self.hasChanged():for observer in self.observers:observer.update()self.clearChanged()def measurementsChanged(self):self.setChanged()self.notifyObservers()self.clearChanged()def setMeasurements(self, temperature, humidity, pressure):self.temperature = temperatureself.humidity = humidityself.pressure = pressureself.measurementsChanged()def getTemperature(self):return self.temperaturedef getHumidity(self):return self.humiditydef getPressure(self):return self.pressuredef setChanged(self):self.changed = Truedef clearChanged(self):self.changed = Falsedef hasChanged(self):return self.changed
displayElement.py
#!/usr/bin/env python# -*- coding:utf-8 -*-from observer import Observerfrom weatherData import WeatherDataclass DisplayElement(object):def display(self):raise NotImplementedError("abstract DisplayElement")class CurrentConditionsDisplay(Observer, DisplayElement):"""目前状况布告板"""def __init__(self, weatherData):self.weatherData = weatherDataself.weatherData.registerObserver(self)def update(self):self.temperature = self.weatherData.getTemperature()self.humidity = self.weatherData.getHumidity()self.display()def display(self):print("Current conditions: " + str(self.temperature) + "F degrees and " + str(self.humidity) + "% humidity")class ForecastDisplay(Observer, DisplayElement):"""天气预报布告板"""def __init__(self, weatherData):self.weatherData = weatherDataself.currentPressure = 29.92self.weatherData.registerObserver(self)def update(self):self.lastPressure = self.currentPressureself.currentPressure = self.weatherData.getPressure()self.display()def display(self):print("Forecast: ");if self.currentPressure > self.lastPressure:print("Improving weather on the way!")elif self.currentPressure == self.lastPressure:print("More of the same")elif self.currentPressure < self.lastPressure:print("Watch out for cooler, rainy weather")class StatisticsDisplay(Observer, DisplayElement):"""气象统计布告板"""def __init__(self, weatherData):self.maxTemp = 0.0self.minTemp = 200self.tempSum = 0.0self.numReadings = 0self.weatherData = weatherDataself.weatherData.registerObserver(self)def update(self):temp = self.weatherData.getTemperature()self.tempSum += tempself.numReadings += 1if temp > self.maxTemp:self.maxTemp = tempif temp < self.minTemp:self.minTemp = tempself.display()def display(self):print("Avg/Max/Min temperature = " + str(self.tempSum / self.numReadings)+ "/" + str(self.maxTemp) + "/" + str(self.minTemp))class HeatIndexDisplay(Observer, DisplayElement):"""酷热指数布告板"""def __init__(self, weatherData):self.weatherData = weatherDataself.weatherData.registerObserver(self)self.heatIndex = 0.0def update(self):t = self.weatherData.getTemperature()rh = self.weatherData.getHumidity()self.heatIndex = self._computeHeatIndex(t, rh)self.display()def _computeHeatIndex(self, t, rh):index = ((16.923 + (0.185212 * t)) + (5.37941 * rh) - (0.100254 * t * rh) + (0.00941695 * (t * t)) + (0.00728898 * (rh * rh)) + (0.000345372 * (t * t * rh)) - (0.000814971 * (t * rh * rh)) +(0.0000102102 * (t * t * rh * rh)) - (0.000038646 * (t * t * t)) + (0.0000291583 * (rh * rh * rh)) +(0.00000142721 * (t * t * t * rh)) + (0.000000197483 * (t * rh * rh * rh)) - (0.0000000218429 * (t * t * t * rh * rh)) +(0.000000000843296 * (t * t * rh * rh * rh)) -(0.0000000000481975 * (t * t * t * rh * rh * rh)))return float(index)def display(self):print("Heat index is " + str(self.heatIndex))
页:
[1]