观察者模式 :定义了内部的对象之间是1:n的关系,当一个对象的状态发生了变化,与这个对象相关联的数据都会同时发生改变。
类似报纸订阅,当订阅报纸后,一有更新就会自动收到,除非退订;这里我们将出版者称为“主题”(Subject),订阅者成为“观察者”(Observer)。
类图:其中的ConcreteSubject就是相关的报纸。
案例:现在要实现一个气象站,观测四个数据,有气压,温度,湿度,可见度,但是有多个地点的公告板,需要使用到其中的数据。当其中的一个数据发生改变,其他的公告板,会马上得到更新。
基本实现如下:
定义基本模型: Subject,Obverser

class Subject: def register(self, observer): pass def deregister(self, observer): pass def notify_observers(self): pass class Observer: def update(self, temperature, humidity, pressure): pass class DisplayElement: def display(self): pass
其中具体主题有WeatherData, 具体的订阅者有AverageDisplay,CurrentDisplay

1 class WeatherData(Subject): 2 def __init__(self): 3 self.observers = [] 4 5 def register(self, observer): 6 if observer not in self.observers: 7 self.observers.append(observer) 8 9 def deregister(self, observer): 10 if observer in self.observers: 11 self.observers.remove(observer) 12 13 def notify_observers(self): 14 for o in self.observers: 15 o.update(self.temperature, self.humidity, self.pressure) 16 17 def data_changed(self): 18 self.notify_observers() 19 20 def set_data(self, temperature, humidity, pressure): 21 self.temperature = temperature 22 self.humidity = humidity 23 self.pressure = pressure 24 self.data_changed() 25 26 27 class CurrentDisplay(Observer, DisplayElement): 28 def __init__(self, weather_data=None): 29 self.weather_data = weather_data 30 self.weather_data.register(self) 31 32 def update(self, temperature, humidity, pressure): 33 self.temperature = temperature 34 self.humidity = humidity 35 self.pressure = pressure 36 self.display() 37 38 def display(self): 39 print "Current Data: temperature=%s, humidity=%s, pressure=%s" % \ 40 (self.temperature, self.humidity, self.pressure) 41 42 class AverageDisplay(Observer, DisplayElement): 43 def __init__(self, weather_data=None): 44 self.temperature = [] 45 self.humidity = [] 46 self.pressure = [] 47 self.weather_data = weather_data 48 self.weather_data.register(self) 49 50 def update(self, temperature, humidity, pressure): 51 self.temperature.append(temperature) 52 self.humidity.append(humidity) 53 self.pressure.append(pressure) 54 self.display() 55 56 def average(self,lst): 57 n = 0 58 for x in lst: 59 n += x 60 return n/len(lst) 61 62 def display(self): 63 print "Average Data: temperature=%s, humidity=%s, pressure=%s" % \ 64 (self.average(self.temperature), \ 65 self.average(self.humidity), \ 66 self.average(self.pressure))
测试

1 if __name__ == '__main__': 2 weather_data = WeatherData() 3 4 current = CurrentDisplay(weather_data) 5 average = AverageDisplay(weather_data) 6 7 weather_data.set_data(18,70,100); print 8 weather_data.set_data(20,70,120); print 9 weather_data.set_data(22,70,80); print 10 weather_data.set_data(24,70,40); print 11 12 weather_data.deregister(average) 13 weather_data.set_data(30,70,100); print 14 weather_data.set_data(40,70,120); print
OK ,Game Over