基本概念
-
觀察者模式中,一個被觀察者管理所有相依於它的觀察者物件,並且在本身的狀態改變時主動發出通知。這通常通過呼叫各觀察者所提供的方法來實現。此種模式通常被用來實現事件處理系統。
-
角色
抽象被觀察者角色:把所有對觀察者物件的引用儲存在一個集合中,每個被觀察者角色都可以有任意數量的觀察者。被觀察者提供一個介面,可以增加和刪除觀察者角色。一般用一個抽象類和介面來實現。
抽象觀察者角色:為所有具體的觀察者定義一個介面,在得到主題的通知時更新自己。
具體被觀察者角色:在被觀察者內部狀態改變時,給所有登記過的觀察者發出通知。具體被觀察者角色通常用一個子類實現。
具體觀察者角色:該角色實現抽象觀察者角色所要求的更新介面,以便使本身的狀態與主題的狀態相協調。通常用一個子類實現。如果需要,具體觀察者角色可以儲存一個指向具體主題角色的引用。
適用場景
1) 當一個抽象模型有兩個方面, 其中一個方面依賴於另一方面。將這二者封裝在獨立的物件中以使它們可以各自獨立地改變和複用。
2) 當對一個物件的改變需要同時改變其它物件, 而不知道具體有多少物件有待改變。
3) 當一個物件必須通知其它物件,而它又不能假定其它物件是誰。換言之, 你不希望這些物件是緊密耦合的。
應用
珠寶商運送一批鑽石,有黃金強盜準備搶劫,珠寶商僱傭了私人保鏢,警察局也派人護送,於是當運輸車上路的時候,強盜保鏢警察都要觀察運輸車一舉一動,
抽象的觀察者
public interface Watcher
{
public void update();
}
抽象的被觀察者,在其中宣告方法(新增、移除觀察者,通知觀察者):
public interface Watched
{
public void addWatcher(Watcher watcher);
public void removeWatcher(Watcher watcher);
public void notifyWatchers();
}
具體的觀察者-保鏢
public class Security implements Watcher
{
@Override
public void update()
{
System.out.println(“運輸車有行動,保安貼身保護");
}
}
具體的觀察者-強盜
public class Thief implements Watcher
{
@Override
public void update()
{
System.out.println(“運輸車有行動,強盜準備動手");
}
}
具體的觀察者-警察
public class Police implements Watcher
{
@Override
public void update()
{
System.out.println(“運輸車有行動,警察護航");
}
}
具體的被觀察者
public class Transporter implements Watched
{
private List<Watcher> list = new ArrayList<Watcher>();
@Override
public void addWatcher(Watcher watcher)
{
list.add(watcher);
}
@Override
public void removeWatcher(Watcher watcher)
{
list.remove(watcher);
}
@Override
public void notifyWatchers(String str)
{
for (Watcher watcher : list)
{
watcher.update();
}
}
}
客戶端
public class Test
{
public static void main(String[] args)
{
Transporter transporter = new Transporter();
Police police = new Police();
Security security = new Security();
Thief thief = new Thief();
transporter.addWatcher(police);
transporter.addWatcher(security);
transporter.addWatcher(security);
transporter.notifyWatchers();
}
}
小結
我推你拉
例子中沒有關於資料和狀態的變化通知,只是簡單通知到各個觀察者,告訴他們被觀察者有行動。
觀察者模式在關於目標角色、觀察者角色通訊的具體實現中,有兩個版本。
一種情況便是目標角色在發生變化後,僅僅告訴觀察者角色“我變化了”,觀察者角色如果想要知道具體的變化細節,則就要自己從目標角色的介面中得到。這種模式被很形象的稱為:拉模式——就是說變化的資訊是觀察者角色主動從目標角色中“拉”出來的。
還有一種方法,那就是我目標角色“服務一條龍”,通知你發生變化的同時,通過一個引數將變化的細節傳遞到觀察者角色中去。這就是“推模式”——管你要不要,先給你啦。
這兩種模式的使用,取決於系統設計時的需要。如果目標角色比較複雜,並且觀察者角色進行更新時必須得到一些具體變化的資訊,則“推模式”比較合適。如果目標角色比較簡單,則“拉模式”就很合適啦。
參考
結語
歡迎關注微信公眾號『碼仔zonE』,專注於分享Java、雲端計算相關內容,包括SpringBoot、SpringCloud、微服務、Docker、Kubernetes、Python等領域相關技術乾貨,期待與您相遇!