HEAD FIRST设计模式之观察者模式

定义

观察者模式有主题和观察者,主题可以订阅多个观察者,当主题发生变化时,通知观察者来做相应改变。

UML图

HEAD FIRST设计模式之观察者模式_第1张图片
Paste_Image.png

定义了一个主题接口,可添加,删除,通知观察者。
定义了一个观察者接口,在收到主题变化通知后,做出变化。

实现例子

拿Head First上面的气象站的例子来说吧。

需要实现的功能大致是这样:

根据气象站的测量接口数据的变化(有个WetherData的类来提供数据),显示天气数据的board必须立即更新。有“目前状况”,“气象统计”,“天气预报”三块board。系统必须可扩展,可随意添加/删除board。

其实,这就比较适合用观察者模式,WetherData为subject,当有更新时,通知到board,来更新数据显示。

github地址在这里,来戳吧

代码如下:

观察者,主题接口

// 主题接口
protocol ISubject {
    func addObserver(observer: BaseObserver)
    func removeObserver(observer: BaseObserver)
    func notifyObservers()
}

// 观察者接口
protocol IObserver {
    func update(subject: ISubject)
}

class BaseObserver: IObserver {
    
    var value: Int = {
        let now = NSDate()
        let timeInterval = now.timeIntervalSince1970 * 100000
        let interval: Int = Int(timeInterval)
        
        print(interval)
        return interval
    }()
    
    func update(subject: ISubject) {
        fatalError("subclass should implement this method")
    }
}

extension BaseObserver: Equatable, Hashable {
    var hashValue: Int {
        return self.value
    }
}

func ==(lhs: BaseObserver, rhs: BaseObserver) -> Bool {
    return lhs.hashValue == rhs.hashValue
}

本来只想定义个IObserver,addObserver(observer: IObserver),但是
removeObserver(observer: IObserver)中,swift没有像oc那样removeObject的方法,只得自己实现Equatable, Hashable来判断是否是同一个对象,来进行删除。所以这里就采用了定义基类BaseObserver,采用时间hash,让其具有唯一性。

如果有其他好的方法欢迎指出

WeatherData

class WeatherData: ISubject {
    
    private var observers: [BaseObserver] = []
    private var temperature: Float = 0
    private var humidity: Float = 0
    private var pressure: Float = 0
    
    func addObserver(observer: BaseObserver) {
        observers.append(observer)
    }
    
    func removeObserver(observer: BaseObserver) {
        observers = observers.filter({
            $0 != observer
        })
    }
    
    func notifyObservers() {
        for observer in observers {
            observer.update(self)
        }
    }
    
    func updateMeasurements(temperature: Float, _ humidity: Float, _ pressure: Float) {
        self.temperature = temperature
        self.humidity = humidity
        self.pressure = pressure
        
        self.notifyObservers()
    }
    
    // 温度
    func getTemperature() -> Float {
        return self.temperature
    }
    
    // 湿度
    func getHumidity() -> Float {
        return self.humidity
    }
    
    // 气压
    func getPressure() -> Float {
        return self.pressure
    }
}

当前状态board,其他的board类似

// 目前状况
class CurrentConditionDisplay: BaseObserver {
    
    init(subject: ISubject) {
        super.init()
        subject.addObserver(self)
    }
    
    override func update(subject: ISubject) {
        if let data = subject as? WeatherData {
            let temperature = data.getTemperature()
            let humidity = data.getHumidity()
            let pressure = data.getPressure()
            
            print("temperature:\(temperature), humidity:\(humidity), pressure:\(pressure)")
        }
    }
}

最终调用:

// observer
let weatherData = WeatherData()
let currentDisplay = CurrentConditionDisplay(subject: weatherData)
let statsticsDisplay = StatsticsDisplay(subject: weatherData)
let forcastDisplay = ForecastDisplay(subject: weatherData)

weatherData.updateMeasurements(10, 1, 200)

输出:

temperature:10.0, humidity:1.0, pressure:200.0

最大气压为:200.0

明天的天气为晴,5~10°,无风

若加上weatherData.removeObserver(currentDisplay)
则不会输出当前状态

最大气压为:200.0

明天的天气为晴,5~10°,无风

你可能感兴趣的:(HEAD FIRST设计模式之观察者模式)