背景

WeatherData对象取得温度、湿度、气压数据,随后更新到三个布告板显示:目前状况、气象统计、天气预报
当有新的测量数据时,WeatherData的measuremeentsChanged方法就会被调用

1.0版本:错误示范

class WeatherData:
    def measurementsChanged(self):
        temp = self.getTemperature();
        humidity = self.getHumidity();
        pressure = self.getPerssure();
        currentConditionsDisplay.update(temp, humidity, pressure);
        statisticsDisplay.update(temp, humidity, pressure);
        forecastDisplay.update(temp, humidity, pressure);

针对具体实现编程,增删布告板必须修改程序
三个update方法是可能改变的地方,没有封装起来

2.0版本:

观察者模式

观察者模式定义了对象之间的一对多依赖。当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新

主题Subject管理数据,当主题对象数据改变时,通知观察者新数据
观察者Observer可以注册主题或取消注册,接收到新数据进行处理

类图

627754141628192528.jpg

优点:主题和观察者之间的松耦合

当有新的观察者时,主题对象不需要修改,只需要新增观察者,并且自己注册为观察者
当观察者变化时,主题对象不需要修改,主题只会通知观察者列表里的对象
当主题对象数据逻辑修改时,观察者不需要修改,观察者只接受数据
在其他地方,可以独立的复用主题或观察者

设计气象站

655912665857196652.jpg

实现气象站

class WeatherData:
    def __init__(self):
        self.observers = []
        self.temperature, self.humidity, self.pressure = 0, 0, 0

    def registerObserver(self, observer):
        self.observers.append(observer)

    def removeObserver(self, observer):
        if observer in self.observers:
            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):
        # test
        self.temperature, self.humidity, self.pressure = temperature, humidity, pressure
        self.measurementsChanged()

class CurrentConditionsDisplay:
    def __init__(self, weatherData):
        self.temperature, self.humidity = 0, 0
        self.weatherData = weatherData
        self.weatherData.registerObserver(self)

    def update(self, temperature, humidity, pressure):
        self.temperature, self.humidity = temperature, humidity
        self.display()

    def display(self):
        print('Current conditions: {}F degrees and {}% humdity'.format(self.temperature, self.humidity))


if __name__ == '__main__':
    weatherDate = WeatherData()
    currentDisplay = CurrentConditionsDisplay(weatherDate)
    weatherDate.setMeasurements(2, 4, 6)
    weatherDate.setMeasurements(1, 34, 46)

3.0版本

增加setchanged方法

可以在更新观察者时,有更多的弹性。比方说,温度计相差半度以上再更新

class WeatherData:
    def __init__(self):
        self.observers = []
        self.temperature, self.humidity, self.pressure = 0, 0, 0
        self.changed = False
        self.MINI_TEMPERATURE_DIFF = 0.5

    def registerObserver(self, observer):
        self.observers.append(observer)

    def removeObserver(self, observer):
        if observer in self.observers:
            self.observers.remove(observer)

    def notifyObservers(self):
        for observer in self.observers:
            observer.update(self.temperature, self.humidity, self.pressure)

    def setChanged(self, temperature, humidity, pressure):
        if abs(temperature - self.    temperature) > self.MINI_TEMPERATURE_DIFF:
            self.temperature, self.humidity, self.pressure = temperature, humidity, pressure
            self.changed = True

    def clearChange(self):
        self.changed = False

    def hasChange(self):
        return self.changed

    def measurementsChanged(self):
        if self.hasChange():
            self.notifyObservers()
            self.clearChange()

    def setMeasurements(self, temperature, humidity, pressure):
        # test
        self.setChanged(temperature, humidity, pressure)
        self.measurementsChanged()

主题推送数据改为观察者拉取数据

好处:观察者不必接受不需要的状态数据;主题新增状态数据时不需要修改所有的观察者调用,只需要新增getter方法;
缺点:观察者多次调用才能凑齐所有需要的数据

class WeatherData:
    def __init__(self):
        self.observers = []
        self.temperature, self.humidity, self.pressure = 0, 0, 0
        self.changed = False
        self.MINI_TEMPERATURE_DIFF = 0.5

    def registerObserver(self, observer):
        self.observers.append(observer)

    def removeObserver(self, observer):
        if observer in self.observers:
            self.observers.remove(observer)

    def notifyObservers(self):
        for observer in self.observers:
            observer.update(self)

    def setChanged(self, temperature, humidity, pressure):
        if abs(temperature - self.    temperature) > self.MINI_TEMPERATURE_DIFF:
            self.temperature, self.humidity, self.pressure = temperature, humidity, pressure
            self.changed = True

    def clearChange(self):
        self.changed = False

    def hasChange(self):
        return self.changed

    def getTemperature(self):
        return self.temperature

    def getHumidity(self):
        return self.humidity

    def getPressure(self):
        return self.pressure

    def measurementsChanged(self):
        if self.hasChange():
            self.notifyObservers()
            self.clearChange()

    def setMeasurements(self, temperature, humidity, pressure):
        # test
        self.setChanged(temperature, humidity, pressure)
        self.measurementsChanged()

class CurrentConditionsDisplay:
    def __init__(self, obs):
        self.temperature, self.humidity = 0, 0
        self.obs = obs
        self.obs.registerObserver(self)

    def update(self, obs):
        if isinstance(obs, WeatherData):
            self.temperature, self.humidity = obs.getTemperature(), obs.getHumidity()
            self.display()

    def display(self):
        print('Current conditions: {}F degrees and {}% humdity'.format(self.temperature, self.humidity))



心碎帅哥
1 声望0 粉丝