設計模式——Observer(觀察者)

內容摘自《設計模式 可複用面向對象軟件的基礎》

類型

行爲型模式

意圖

定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新。

適用性

當出現以下情況時可考慮使用該模式:

  • 一個抽象模型有兩個方面,其中一個方面依賴於另一個方面。將二者獨立封裝在各自的類中,使其可以獨立的改變和複用。
  • 對一個對象的改變必須要同時改變其他對象,而不知道具體有多少對象需要被改變。
  • 一個對象必須通知其他對象,又不能假定其他對象是誰,換言之就是不希望這些對象緊密耦合在一起。

參與者

  • Subject(目標)
    目標知道它的觀察者。一個目標可以有任意多個觀察者。
    提供註冊和刪除觀察者對象的接口。
  • Observer(觀察者)
    爲那些在目標發生改變時需要獲得通知的對象定義一個更新接口。
  • ConcreteSubject(具體目標)
    將有關狀態存入各ConcreteObserver對象。
    當它的對象發生改變時,向其各個觀察者發出通知。
  • ConcreteObserver(具體觀察者)
    維護一個指向ConcreteSubject的引用。
    存儲有關狀態,這些狀態應與目標的狀態保持一致。
    實現Observer的更新接口,以使自身狀態與目標狀態保持一致。

協作

  • 當ConcreteSubject發生任何可能導致其觀察者與其本身狀態不一致的改變時,它將通知它的各個觀察者。
  • 在得到一個具體的改變通知後,ConcreteObserver對象可向目標對象查詢信息。ConcreteObserver使用這些信息以使它的狀態與目標對象的狀態一致。

效果

  • 目標和觀察者間的抽象耦合
    對於目標而言,只知道自己有一系列Observer,不知道其具體的類,這使得目標與觀察者的耦合變得最小。
  • 支持廣播通信
    目標發送的通知,不需要指定它的接收者,只需要通知登記了的觀察者對象,目標對象也不感興趣有多少對象對自己感興趣,僅有的責任就是通知所有觀察者。這帶來了在任何時刻增刪觀察者的自由,如何處理通知,由每一個觀察者自己決定。
  • 意外的更新
    因爲觀察者不知道有其他觀察者存在,對於改變目標狀態的代價一無所知,這可能會導致其他依賴於目標狀態的一系列觀察者出現意外的更新,而且難以捕捉。

Demo

假設飛機存在起飛、飛行中、降落三種信號狀態,乘客、空乘、地勤人員會關注這些狀態,每當狀態改變時,三種人員會做出對應的行爲。

/**
 * 信號
 */

public abstract class Signal {

    private List<Observer> observers;

    public Signal() {
        this.observers = new ArrayList<Observer>();
    }

    public void attach(Observer observer) {
        observers.add(observer);
    }

    public void detach(Observer observer) {
        observers.remove(observer);
    }

    public void notifyObserver() {
        observers.stream().forEach(o -> {
            o.prepare();
        });
    }
}

/**
 * 飛機指示信號
 */

public class PlaneSignal extends Signal {

    // blue-準備起飛;yellow-準備降落;white-飛行中;
    private String colorSignal;

    public String getColorSignal() {
        return colorSignal;
    }

    public void setColorSignal(String colorSignal) {
        this.colorSignal = colorSignal;
        notifyObserver();
    }

}
public abstract class Observer {

    protected Signal signal;

    public void subscribe(Signal sig) {
        this.signal = sig;
        signal.attach(this);
    }

    public void unSubscribe(Signal sig) {
        sig.detach(this);
    }

    abstract void prepare();
}
/**
 * 乘客
 */

public class Passenger extends Observer {

    @Override
    void prepare() {
        PlaneSignal sig = (PlaneSignal) signal;

        System.out.print("乘客:");
        switch (sig.getColorSignal()) {
        case "blue":
            System.out.println("飛機準備起飛,我要放好行李,綁好安全帶");
            break;
        case "yellow":
            System.out.println("飛機準備降落,綁好安全帶,確認走時不會忘記行李");
            break;
        default:
            System.out.println("飛機飛行中,打個盹兒吧");
            break;
        }
    }

}
/**
 * 空乘
 */

public class Stewardess extends Observer {

    @Override
    void prepare() {
        PlaneSignal sig = (PlaneSignal) signal;

        System.out.print("空乘:");
        switch (sig.getColorSignal()) {
        case "blue":
            System.out.println("飛機準備起飛,我要提醒乘客關機,綁好安全帶");
            break;
        case "yellow":
            System.out.println("飛機準備降落,我要提醒乘客,不要忘記行李");
            break;
        default:
            System.out.println("飛機飛行中,我要去進行派餐服務");
            break;
        }
    }

}
/**
 * 地勤人員
 */

public class GroundStaff extends Observer {

    @Override
    void prepare() {
        PlaneSignal sig = (PlaneSignal) signal;

        System.out.print("地勤:");
        switch (sig.getColorSignal()) {
        case "blue":
            System.out.println("飛機準備起飛,我要快點把托運行李放好");
            break;
        case "yellow":
            System.out.println("飛機準備降落,我要準備接機,運輸行李");
            break;
        default:
            System.out.println("飛機飛行中,下一班飛機還有一會,摸個魚吧");
            break;
        }
    }

}

主程序

public class App {

    public static void main(String[] args) {
        PlaneSignal signal = new PlaneSignal();
        Passenger passenger = new Passenger();
        Stewardess stewardess = new Stewardess();
        GroundStaff groundStaff = new GroundStaff();
        passenger.subscribe(signal);
        stewardess.subscribe(signal);
        groundStaff.subscribe(signal);
        
        System.out.println("--------3個觀察者,準備起飛--------");
        signal.setColorSignal("blue");
        
        System.out.println("--------2個觀察者,準備降落--------");
        passenger.unSubscribe(signal);
        signal.setColorSignal("yellow");
        
        System.out.println("--------1個觀察者,飛行中--------");
        groundStaff.unSubscribe(signal);
        signal.setColorSignal("white");
    }

}

結果爲:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章