一、概述
觀察者模式,又可以稱之為發布-訂閱模式,觀察者,顧名思義,就是一個監聽者,類似監聽器的存在,一旦被觀察/監聽的目標發生的情況,就會被監聽者發現,這么想來目標發生情況到觀察者知道情況,其實是由目標將情況發送到觀察者的。
觀察者模式多用于實現訂閱功能的場景,例如微博的訂閱,當我們訂閱了某個人的微博賬號,當這個人發布了新的消息,就會通知我們。
現在我們舉一個類似的情況,并使用代碼來實現,為大家提供一個比較明顯的認識。
二、示例
警察在找到嫌犯的時候,為了找到幕后主使,一般都會蹲點監察,這里我有三名便衣警察來蹲點監察2名嫌犯,三名便衣分別是:張昊天、石破天、趙日天,兩名嫌犯是:大熊與黑狗,詳見代碼:
觀察者接口:Observer
public interface Observer {
void update(String message,String name);
}
定義三名便衣觀察者:Bianyi1、Bianyi2、Bianyi3
/**
* 便衣警察張昊天
*/
public class Bianyi1 implements Observer {
//定義姓名
private String bname = "張昊天";
@Override
public void update(String message,String name) {
System.out.println(bname+":"+name+"那里有新情況:"+ message);
}
}
/**
* 便衣警察石破天
*/
public class Bianyi2 implements Observer {
//定義姓名
private String bname = "石破天";
@Override
public void update(String message,String name) {
System.out.println(bname+":"+name+"那里有新情況:"+ message);
}
}
/**
* 便衣警察趙日天
*/
public class Bianyi3 implements Observer {
//定義姓名
private String bname = "趙日天";
@Override
public void update(String message,String name) {
System.out.println(bname+":"+name+"那里有新情況:"+ message);
}
}
目標接口:Huairen
public interface Huairen {
//添加便衣觀察者
void addObserver(Observer observer);
//移除便衣觀察者
void removeObserver(Observer observer);
//通知觀察者
void notice(String message);
}
定義兩個嫌疑犯:XianFan1、XianFan2
import JAVA.util.*;
/**
* 嫌犯大熊
*/
public class XianFan1 implements Huairen {
//別稱
private String name = "大熊";
//定義觀察者集合
private List<Observer> observerList = new ArrayList<Observer>();
//增加觀察者
@Override
public void addObserver(Observer observer) {
if(!observerList.contains(observer)){
observerList.add(observer);
}
}
//移除觀察者
@Override
public void removeObserver(Observer observer) {
if(observerList.contains(observer)){
observerList.remove(observer);
}
}
//通知觀察者
@Override
public void notice(String message) {
for(Observer observer:observerList){
observer.update(message,name);
}
}
}
import java.util.*;
/**
* 嫌犯黑狗
*/
public class XianFan2 implements Huairen {
//別稱
private String name = "黑狗";
//定義觀察者集合
private List<Observer> observerList = new ArrayList<Observer>();
//增加觀察者
@Override
public void addObserver(Observer observer) {
if(!observerList.contains(observer)){
observerList.add(observer);
}
}
//移除觀察者
@Override
public void removeObserver(Observer observer) {
if(observerList.contains(observer)){
observerList.remove(observer);
}
}
//通知觀察者
@Override
public void notice(String message) {
for(Observer observer:observerList){
observer.update(message,name);
}
}
}
測試類:Clienter
public class Clienter {
public static void main(String[] args) {
//定義兩個嫌犯
Huairen xf1 = new XianFan1();
Huairen xf2 = new XianFan2();
//定義三個觀察便衣警察
Observer o1 = new Bianyi1();
Observer o2 = new Bianyi2();
Observer o3 = new Bianyi3();
//為嫌犯增加觀察便衣
xf1.addObserver(o1);
xf1.addObserver(o2);
xf2.addObserver(o1);
xf2.addObserver(o3);
//定義嫌犯1的情況
String message1 = "又賣了一批貨";
String message2 = "老大要下來視察了";
xf1.notice(message1);
xf2.notice(message2);
}
}
測試結果:
張昊天:大熊那里有新情況:又賣了一批貨
石破天:大熊那里有新情況:又賣了一批貨
張昊天:黑狗那里有新情況:老大要下來視察了
包拯:黑狗那里有新情況:老大要下來視察了
三、模式解析
通過上面的實例可以很明顯地看出,觀察者模式的大概模型,關鍵是什么呢?
關鍵點:
- 針對觀察者與被觀察者分別定義接口,有利于分別進行擴展。
- 重點就在被觀察者的實現中: 定義觀察者集合,并定義針對集合的添加、刪除操作,用于增加、刪除訂閱者(觀察者) 定義通知方法,用于將新情況通知給觀察者用戶(訂閱者用戶)
- 觀察者中需要有個接收被觀察者通知的方法。
如此而已!
觀察者模式定義的是一對多的依賴關系,一個被觀察者可以擁有多個觀察者,并且通過接口對觀察者與被觀察者進行邏輯解耦,降低二者的直接耦合。
如此這般,想了一番之后,突然發現這種模式與橋接模式有點類似的感覺。
橋接模式也是擁有雙方,同樣是使用接口(抽象類)的方式進行解耦,使雙方能夠無限擴展而互不影響,其實二者還是有者明顯的區別:
- 主要就是使用場景不同,橋接模式主要用于實現抽象與實現的解耦,主要目的也正是如此,為了雙方的自由擴展而進行解耦,這是一種多對多的場景。觀察者模式側重于另一方面的解耦,側重于監聽方面,側重于一對多的情況,側重于一方發生情況,多方能獲得這個情況的場景。
- 另一方面就是編碼方面的不同,在觀察者模式中存在許多獨有的內容,如觀察者集合的操作,通知的發送與接收,而在橋接模式中只是簡單的接口引用。