HEAD FIRST設(shè)計(jì)模式之觀察者模式

定義

觀察者模式有主題和觀察者,主題可以訂閱多個(gè)觀察者,當(dāng)主題發(fā)生變化時(shí),通知觀察者來做相應(yīng)改變。

UML圖

Paste_Image.png

定義了一個(gè)主題接口,可添加,刪除,通知觀察者。
定義了一個(gè)觀察者接口,在收到主題變化通知后,做出變化。

實(shí)現(xiàn)例子

拿Head First上面的氣象站的例子來說吧。

需要實(shí)現(xiàn)的功能大致是這樣:

根據(jù)氣象站的測量接口數(shù)據(jù)的變化(有個(gè)WetherData的類來提供數(shù)據(jù)),顯示天氣數(shù)據(jù)的board必須立即更新。有“目前狀況”,“氣象統(tǒng)計(jì)”,“天氣預(yù)報(bào)”三塊board。系統(tǒng)必須可擴(kuò)展,可隨意添加/刪除board。

其實(shí),這就比較適合用觀察者模式,WetherData為subject,當(dāng)有更新時(shí),通知到board,來更新數(shù)據(jù)顯示。

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
}

本來只想定義個(gè)IObserver,addObserver(observer: IObserver),但是
removeObserver(observer: IObserver)中,swift沒有像oc那樣removeObject的方法,只得自己實(shí)現(xiàn)Equatable, Hashable來判斷是否是同一個(gè)對(duì)象,來進(jìn)行刪除。所以這里就采用了定義基類BaseObserver,采用時(shí)間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
    }
}

當(dāng)前狀態(tài)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)")
        }
    }
}

最終調(diào)用:

// 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°,無風(fēng)

若加上weatherData.removeObserver(currentDisplay)
則不會(huì)輸出當(dāng)前狀態(tài)

最大氣壓為:200.0

明天的天氣為晴,5~10°,無風(fēng)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容