觀察者模式的實(shí)現(xiàn)

當(dāng)對(duì)象間存在一對(duì)多關(guān)系時(shí),則使用觀察者模式(Observer Pattern)。比如,當(dāng)一個(gè)對(duì)象被修改時(shí),則會(huì)自動(dòng)通知它的依賴對(duì)象。觀察者模式屬于行為型模式。

介紹

意圖:定義對(duì)象間一種一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都得到通知并自動(dòng)更新。

主要解決:一個(gè)對(duì)象狀態(tài)改變給其他對(duì)象通知的問題,而且要考慮到易用和低耦合,保證高度的寫作。

何時(shí)使用:一個(gè)對(duì)象(目標(biāo)對(duì)象)的狀態(tài)發(fā)生改變,所有的依賴對(duì)象(觀察者對(duì)象)都將得到通知,進(jìn)行廣播通知。

關(guān)鍵代碼:在抽象類里有一個(gè)ArrayList存放著觀察者們。

優(yōu)點(diǎn):1.觀察者和被觀察者是抽象耦合的。2.建立一套觸發(fā)機(jī)制。

缺點(diǎn):1.如果一個(gè)被觀察者對(duì)象有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會(huì)花費(fèi)很多時(shí)間。2.如果在觀察者和觀察目標(biāo)之間有循環(huán)依賴的話,觀察目標(biāo)會(huì)觸發(fā)它們之間進(jìn)行循環(huán)使用,可能導(dǎo)致系統(tǒng)崩潰。3.觀察者模式?jīng)]有相應(yīng)的機(jī)制讓觀察者知道所觀察的目標(biāo)對(duì)象時(shí)怎么發(fā)生的,而僅僅只是知道觀察目標(biāo)發(fā)生了變化。

使用場(chǎng)景

  • 一個(gè)抽象模型有兩個(gè)方面,其中一個(gè)方面依賴于另一個(gè)方面。將這些方面封裝在獨(dú)立的對(duì)象中使它們可以各自獨(dú)立的改變和復(fù)用。
  • 一個(gè)對(duì)象的改變將導(dǎo)致其他一個(gè)或多個(gè)對(duì)象也發(fā)生改變,而不知道具體有多少對(duì)象將發(fā)生改變,可以降低對(duì)象之間的耦合度。
  • 一個(gè)對(duì)象必須通知其他對(duì)象,而并不知道這些對(duì)象是誰。
  • 需要在系統(tǒng)中創(chuàng)建一個(gè)觸發(fā)鏈,A對(duì)象的行為將影響B(tài)對(duì)象,B對(duì)象的行為將影響C對(duì)象....,可以使用觀察者模式創(chuàng)建一種鏈?zhǔn)接|發(fā)機(jī)制。

注意事項(xiàng):1.java中已經(jīng)有了對(duì)觀察者模式的支持類。2.避免循環(huán)使用。3.如果順序執(zhí)行,某一個(gè)觀察者錯(cuò)誤會(huì)導(dǎo)致系統(tǒng)卡殼,一般采用異步方式。

Java實(shí)現(xiàn)

觀察者模式使用三個(gè)類Subject、Observer和Client。Subject對(duì)象帶有綁定觀察者到Client對(duì)象和從Client對(duì)象解綁觀察者的方法。我們創(chuàng)建Subject類、Observer抽象類和擴(kuò)展了抽象類Observer的實(shí)體類。

步驟一

創(chuàng)建Subject類。

// Subject.java
import java.util.ArrayList;
import java.util.List;

public class Subject {
    private List<Observer> observers = new ArrayList<Observer>();
    private int state;
    
    public int getState() {
        return state;
    }
    
    public void setState(int state) {
        this.state = state;
        notifyAllObservers();
    }
    
    public void attach(Observer observer) {
        observers.add(observer);
    }
    
    public void notifyAllObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}

步驟二

創(chuàng)建Observer類

// Observer.java
public abstract class Observer {
    protected Subject subject;
    public abstract void update();
}

步驟三

創(chuàng)建實(shí)體觀察類

// BinaryObserver.java
public class BinaryObserver extends Observer {
    public BinaryObserver(Subject subject) {
        this.subject = subject;
        this.subject.attach(this);
    }
    
    @Override
    public void update() {
        System.out.println("Binary String:" + Integer.toBinaryString(subject.getState()));
    }
}
// OctalObserver.java
public class OctalObserver extends Observer {
    public OctalObserver(Subject subject) {
        this.subject = subject;
        this.subject.attach(this);
    }
    
    @Override
    public void update() {
        System.out.println("Octal String: " + INteger.toOctalString(subject.getState()));
    }
}
// HexaObserver.java
public class HexaObserver extends Observer {
    public HexaObserver(Subject subject) {
        this.subject = subject;
        this.subject.attach(this);
    }
    
    @Override
    public void update() {
        System.out.println("Hex String: " + Integer.toHexString(subject.getState()).toUpperCase());
    }
}

步驟四

使用subject和實(shí)體觀察者對(duì)象

// ObserverPatternDemo.java
public class ObserverPatternDemo {
    public static void main(String[] args) {
        Subject subject = new Subject();
        
        new HexaObserver(subject);
        new OctalObserver(subject);
        new BinaryObserver(subject);
        
        System.out.println("First State change: 15");
        subject.setState(15);
        System.out.println("Second state change: 10");
        subject.setState(10);
    }
}

步驟5

執(zhí)行程序,輸出結(jié)果

First state change : 15
Hex String: F
Octal String: 17
Binary String: 1111
Second state change : 10
Hex String: A
Octal String: 12
Binary String: 010

ES6下javascript的實(shí)現(xiàn)

// 聲明EventEmitter時(shí)間發(fā)生器構(gòu)造函數(shù)
function EventEmitter() {
    this._events = Object.create(null);
}

// 設(shè)置最大監(jiān)聽數(shù)
EventEmitter.prototype.setMaxListeners = function(n) {
    this._count = n;
}

// 得到最大監(jiān)聽數(shù)
EventEmitter.prototype.getMaxListeners = function(n) {
    return this._count ? this._count : EventEmitter.defaultMaxListeners;
}

// eventName方法
EventEmitter.prototype.eventNames = function() {
    return Object.keys(this._events);
}

// on 訂閱方法的實(shí)現(xiàn),跟addListener相同
EventEmitter.prototype.adddListener = EventEmitter.prototype.on = function(type, callback, flag) {
    // 如果實(shí)例不存在則創(chuàng)建一個(gè)空對(duì)象,Object.create(null)沒有鏈
    if (!this._events) {
        this._events = Object.create(null);
    }
    
    // 不是newListener 就應(yīng)該讓newListener執(zhí)行下
    if (type !== "newListener") {
        if (this._events["newListener"]) {
            this._events["newListener"].forEach(fn => fn(type))
        }
    }
    
    // flag 標(biāo)識(shí)
    if (this._events[type]) {
        if (flag) {
            this._events[type].unshift(callback);
        } else {
            this._events[type].push(callback);
        }
    } else {
        // 內(nèi)部未存放
        this._events[type] = [callback];
    }
    if (this._events[type].length === this.getMaxListeners()) {
        console.warn('內(nèi)存泄露');
    }
};

// once 實(shí)現(xiàn)
EventEmitter.prototype.once = function(type, callback, flag) {
    let one = (...args) => {
        callback(...args);
        this.removeListener(type, one);
    }
    
    // 自定義屬性 因?yàn)閷?shí)例中沒有wrap屬性
    one.l = callback;
    this.on(type, one, flag);
};
// prependListener方法實(shí)現(xiàn)
EventEmitter.prototype.prependOnceListener  = function(type,callback){
    this.once(type,callback,true);
};
// emit方法實(shí)現(xiàn)
EventEmitter.prototype.emit = function(type,...args){
    if(this._events[type]){ //{失戀:[cry,eat]} 如果失戀對(duì)應(yīng)有值,依次執(zhí)行里面的方法
        this._events[type].forEach(fn=>fn(...args))
    }
};
// 移除訂閱事件的方法
EventEmitter.prototype.removeListener = function(type,callback){
    if(this._events[type]){
        // 返回false就表示不要了,用filter實(shí)現(xiàn)去重
        this._events[type] = this._events[type].filter(fn=>fn!==callback && fn.l!==callback)
    }
};
// removeAllListeners 移除所有的監(jiān)聽者
EventEmitter.prototype.removeAllListeners = function(){
    this._events = Object.create(null);
};
// listeners 方法
EventEmitter.prototype.listeners = function(type){
  return this._events[type];
};
module.exports = EventEmitter;
?著作權(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),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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