Head First 设计模式——观察者模式(Observer Pattern)——Python实现(1)

本作品采用知识共享署名-非商业性使用-相同方式共享 3.0 Unported许可协议进行许可。允许非商业转载,但应注明作者及出处。


作者:liuyuan_jq

2011-06-13


观察者模式定义

定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖都会收到通知并自动更新。观察者模式提供了一种对象设计,让主题和观察者之间松耦合。


设计原则

为了交互对象之间的松耦合设计而努力。松耦合的设计之所以能让我们建立有弹性的系统,能够应对变化,是因为对象之间的互相依赖降到了最低。


问题

建立下一代Internet气象观察站,该气象站必须建立在我们专利申请中的WeatherData对象上,由WeatherData对象负责追踪目前的天气状况(温度,湿度,气压)。

  • 建立一个应用,有三种布告板,分别显示目前的状态、气象统计及简单的预报。
  • 当WeatherObject对象获得最新的测量数据时,三种布告板必须实时更新。
  • 公布一组API,让其他开发人员可以写出自己的气象布告板。

设计气象站

WeatherData实现Subject接口

class Subject(object): """ 主题接口类 """ def registerObserver(observer): raise NotImplementedError("abstract Subject") def removeObserver(observer): raise NotImplementedError("abstract Subject") def notifyObservers(self): raise NotImplementedError("abstract Subject")

气象组件实现观察者接口

class Observer(object): """ 观察者接口类 """ def update(temp, humidity, pressure): raise NotImplementedError("abstract Observer")

布告栏显示接口

class DisplayElement(object): def display(self): raise NotImplementedError("abstract DisplayElement")


源代码具体实现

subject.py

#!/usr/bin/env python # -*- coding:utf-8 -*- class Subject(object): """ 主题接口类 """ def registerObserver(observer): raise NotImplementedError("abstract Subject") def removeObserver(observer): raise NotImplementedError("abstract Subject") def notifyObservers(self): raise NotImplementedError("abstract Subject")

observer.py

#!/usr/bin/env python # -*- coding:utf-8 -*- class Observer(object): """ 观察者接口类 """ def update(temp, humidity, pressure): raise NotImplementedError("abstract Observer")

weatherData.py

#!/usr/bin/env python # -*- coding:utf-8 -*- from subject import Subject class WeatherData(Subject): """ 天气数据类,是一个主题类 """ # 类静态成员 observers = [] def __init__(self): self.temperature = 0.0 self.humidity = 0.0 self.pressure = 0.0 def registerObserver(self, observer): """ 注册观察者对象 """ self.observers.append(observer) def removeObserver(self, observer): """ 注销观察者对象 """ self.observers.remove(observer) def notifyObservers(self): """ 通知所有的观察者对象 """ for observer in self.observers: observer.update(self.temperature, self.humidity, self.pressure) def measurementsChanged(self): self.notifyObservers() def setMeasurements(self, temperature, humidity, pressure): self.temperature = temperature self.humidity = humidity self.pressure = pressure self.measurementsChanged() def getTemperature(self): return self.temperature def getHumidity(self): return self.humidity def getPressure(self): return self.pressure

displayElement.py

#!/usr/bin/env python # -*- coding:utf-8 -*- from observer import Observer from weatherData import WeatherData class DisplayElement(object): def display(self): raise NotImplementedError("abstract DisplayElement") class CurrentConditionsDisplay(Observer, DisplayElement): """ 目前状况布告板 """ def __init__(self, weatherData): self.weatherData = weatherData self.weatherData.registerObserver(self) def update(self, temperature, humidity, pressure): self.temperature = temperature self.humidity = humidity 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 = weatherData self.currentPressure = 29.92 self.weatherData.registerObserver(self) def update(self, temp, humidity, pressure): self.lastPressure = self.currentPressure self.currentPressure = pressure 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.0 self.minTemp = 200 self.tempSum = 0.0 self.numReadings = 0 self.weatherData = weatherData self.weatherData.registerObserver(self) def update(self, temp, humidity, pressure): self.tempSum += temp self.numReadings += 1 if temp > self.maxTemp: self.maxTemp = temp if temp < self.minTemp: self.minTemp = temp self.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 = weatherData self.weatherData.registerObserver(self) self.heatIndex = 0.0 def update(self, t, rh, pressure): 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))


测试

weatherStation.py

#!/usr/bin/env python # -*- coding:utf-8 -*- from weatherData import WeatherData from displayElement import * weatherData = WeatherData() currentDisplay = CurrentConditionsDisplay(weatherData) statisticsDisplay = StatisticsDisplay(weatherData) forecastDisplay = ForecastDisplay(weatherData) weatherData.setMeasurements(80, 65, 30.4) weatherData.setMeasurements(82, 70, 29.2) weatherData.setMeasurements(78, 90, 29.2)

Current conditions: 80F degrees and 65% humidity Avg/Max/Min temperature = 80.0/80/80 Forecast: Improving weather on the way! Current conditions: 82F degrees and 70% humidity Avg/Max/Min temperature = 81.0/82/80 Forecast: Watch out for cooler, rainy weather Current conditions: 78F degrees and 90% humidity Avg/Max/Min temperature = 80.0/82/78 Forecast: More of the same

weatherStationHeatIndex.py

#!/usr/bin/env python # -*- coding:utf-8 -*- from weatherData import WeatherData from displayElement import * weatherData = WeatherData() currentDisplay = CurrentConditionsDisplay(weatherData) statisticsDisplay = StatisticsDisplay(weatherData) forecastDisplay = ForecastDisplay(weatherData) heatIndexDisplay = HeatIndexDisplay(weatherData) weatherData.setMeasurements(80, 65, 30.4) weatherData.setMeasurements(82, 70, 29.2) weatherData.setMeasurements(78, 90, 29.2)

Current conditions: 80F degrees and 65% humidity Avg/Max/Min temperature = 80.0/80/80 Forecast: Improving weather on the way! Heat index is 82.9553506371 Current conditions: 82F degrees and 70% humidity Avg/Max/Min temperature = 81.0/82/80 Forecast: Watch out for cooler, rainy weather Heat index is 86.9012330639 Current conditions: 78F degrees and 90% humidity Avg/Max/Min temperature = 80.0/82/78 Forecast: More of the same Heat index is 83.6496713956

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值