多個物件之間存在著一對多的依賴關係,當一個物件發生改變時,所有跟他有關的物件都會被通知且更新。
現實生活中就有許多觀察者模式的案例,例如:訂閱youtuber,發布新影片就會接收到通知;加入Line官方帳號,會接收到優惠訊息...等等。
| name | description | 
|---|---|
| Subject | 抽象目標,提供保存觀察者物件的集合以及增加觀察者物件的方法、刪除觀察者物件的方法以及通知所有觀察者的抽象方法。 | 
| ConcreteSubject | 具體目標,實作抽象目標中的通知方法。具體目標內部發生改變時會通知所有加入的觀察者物件。 | 
| Observer | 抽象觀察者,可以是抽象類別或是介面。含有更新自己的抽象方法。 | 
| ConcreteObserver | 實作抽象觀察者,在目標更改狀態時接收通知並更改自身狀態。 | 

就拿現在很紅的Youtuber來做範例,Peeta葛格是一個Youtuber,我們訂閱了之後,就可以接收到他發片的通知,所以Peeta是目標,而我們是觀察者。廠商也訂閱了Peeta,他想知道Peeta發片時是不是葉配影片,所以廠商也是觀察者。
import java.util.*;
enum Type { // 建立列舉方便等等程式使用
    BUSINESS, VLOG
}
//抽象目標:分別有存放觀察者的集合以及增加、刪除、通知觀察者的方法
abstract class Subject {
    protected List<Observer> observers = new ArrayList<Observer>();   
    //增加觀察者
    public void add(Observer observer) {
        observers.add(observer);
    }    
    //刪除觀察者
    public void remove(Observer observer) {
        observers.remove(observer);
    }   
    public abstract void notifyObserver(Type type); //通知觀察者
}
//實體目標 Peeta葛格:實作抽象目標,通知觀察者的方法。
class YoutuberPeeta extends Subject {
    public void notifyObserver(Type type) {
        String videoType = null;
        switch(type){
            case BUSINESS:
                videoType = "葉配";
                break;
            case VLOG:
                videoType = "vlog";
                break;
        }
        System.out.println("Peeta 發布新" + videoType + "影片");
        System.out.println("--------------");       
       
        for(Object obs:observers) {
            ((Observer)obs).response(type);
        }
       
    }          
}
//抽象觀察者:定義接收到目標時的方法。
interface Observer {
    void response(Type type); //反應
}
//實體觀察者 粉絲
class Fans implements Observer {
    public void response(Type type) {
        switch(type){
            case BUSINESS:
                System.out.println("紛絲看到葉配表示傷心!");
                break;
            case VLOG:
                System.out.println("紛絲看到VLOG覺得有趣!");
                break;
        }
    }
}
//實體觀察者:廠商
class Vendor implements Observer {
    public void response(Type type) {
                switch(type){
            case BUSINESS:
                System.out.println("廠商看到葉配覺得開心!");
                break;
            case VLOG:
                System.out.println("廠商看到VLOG表示為啥不是葉配!");
                break;
        }
    }
}
// Client分別建立目標及兩個觀察者,而目標在發布新影片時會同時通知兩個觀察者
public class ObserverPattern {
    public static void main(String[] args) {
        Subject subject = new YoutuberPeeta();
        Observer obs1 = new Fans();
        Observer obs2 = new Vendor();
        subject.add(obs1);
        subject.add(obs2);
        subject.notifyObserver(Type.BUSINESS);
        System.out.println();    
        subject.notifyObserver(Type.VLOG);
    }
}
output
Peeta 發布新葉配影片
--------------
紛絲看到葉配表示傷心!
廠商看到葉配覺得開心!
Peeta 發布新vlog影片
--------------
紛絲看到VLOG覺得有趣!
廠商看到VLOG表示為啥不是葉配!
多個物件之間存在著一對多的依賴關係,當一個物件發生改變時,所有跟他有關的物件都會被通知且更新。
Subject:抽象目標,提供保存觀察者物件的集合以及增加觀察者物件的方法、刪除觀察者物件的方法以及通知所有觀察者的抽象方法。
ConcreteSubject:具體目標,實作抽象目標中的通知方法。具體目標內部發生改變時會通知所有加入的觀察者物件。
Observer:抽象觀察者,可以是抽象類別或是介面。含有更新自己的抽象方法。
ConcreteObserver:實作抽象觀察者,在目標更改狀態時接收通知並更改自身狀態。
優點
1. 降低目標與觀察者間的耦合關係,兩者之間為抽象耦合關係。
2. 目標與觀察者間建立了一套觸發機制。
缺點
1. 目標與觀察者間的依賴並無完全切除。
2. 當觀察者物件多時,會影響效能。
1. 物件之間存在一對多的關係,一個物件狀態改變會影響其他物件時。