java設計模式-觀察者模式
1.觀察者模式
觀察者模式(Observer),即多個觀察者物件監聽一個共同的主題物件,是一種一對多的依賴關係。當被觀察的主題物件發生改變時,會通過回掉函式通知所有關注自己的觀察者,觀察者會主動根據接受到的通知訊息更新自己。
觀察者模式屬於行為型模式,又叫釋出-訂閱(Publish/Subscribe)模式、模型-檢視 (Model/View)模式、源-監聽器(Source/Listener)模式或從屬者(Dependents)模式。
觀察者模式在java中很常用,而且java jdk也對它做了實現,可見該設計模式的重要位置。為了實現檢視和事件處理的分離,大多都採用了 Observer模式。
2.模式結構圖
結構包括四個類,兩個抽象類,兩個具體類。
Observable抽象主題-被觀察者,用於儲存觀察者物件的引用,可以添加註冊和刪除觀察者,用於儲存和刪除對觀察者的引用。
ConcreteSubject具體主題-被觀察者,被觀察者主題內部狀態發生改變時,會對所有登記註冊的觀察者發出通知。
Observer抽象觀察者,給所有的具體觀察者定義一個藉口,並定義一個更新自己的方法。
ConcreteObserver具體觀察者,實現抽象觀察者角色所需要的更新介面update
觀察者(Observer)相當於事件監聽者(監聽器),被觀察者(Observable)相當於事件源和事件,執行邏輯時通知observer即可觸發oberver的update,同時可傳被觀察者和引數。簡化了事件-監聽模式的實現。
3.訂閱微信公眾號的示例
觀察者模式,又叫釋出訂閱模式,這裡使用“微信公眾號釋出資訊,關注者收到資訊通知”為例。
以下觀察者模式的實現,類似於了jdk的實現方式。
定義1:抽象被觀察者介面和抽象觀察者介面
package observerDemo.business; /** * @desc:抽象被觀察者 */ public interface Observable { public void registerObserver(Observer o); public void removeObserver(Observer o); public void notifyObserver(); public void notifyObservers(Object obj); } /** * @desc:抽象觀察者 */ public interface Observer { void update(Observable o, Object arg); }
定義2:實現類,定義具體被觀察者(微信公眾號)和觀察者(微信使用者)
package observerDemo.business.impl;
import observerDemo.business.Observable;
import observerDemo.business.Observer;
import java.util.Vector;
/**
* @desc: 微信公眾號
*/
public class AccountOfficalSubject implements Observable {
private Vector obs; //存放觀察者的陣列
public AccountOfficalSubject() {
obs = new Vector();
}
/** * 新增觀察者(執行緒安全) */
@Override
public synchronized void registerObserver(Observer o){
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
/** * 刪除觀察者(執行緒安全) */
@Override
public synchronized void removeObserver(Observer o){
obs.removeElement(o);
}
/** * 喚醒(通知)觀察者(執行緒安全) */
@Override
public void notifyObserver(){
//發生了業務,並將業務資訊通知給訂閱者
notifyObservers(null);
}
@Override
public void notifyObservers(Object arg){
Object[] arrLocal;
arrLocal = obs.toArray();
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
/** * 觀察者(訂閱者數量,關注人數) */
public synchronized int countObservers() {
return obs.size();
}
}
/**
* @desc: 微信個人賬號
*/
public class WeChartObserver implements Observer {
private String ID;
public WeChartObserver(){}
public WeChartObserver(String ID){
this.ID=ID;
}
@Override
public void update(Observable o, Object arg){
System.out.println("微訊號:"+ID);
if(arg!=null){
System.out.println("收到訂閱資訊:"+arg.toString());
}
}
}
定義3:定義一個微信公眾號釋出的資訊實體類
package observerDemo.dto;
/**
* @desc: 公眾號釋出的動態短文
*/
public class ArticleDTO {
private String theme; //主題
private String author; //作者
private String content; //訊息內容
private Long reading; //閱讀量
public ArticleDTO(String theme, String author, String content, Long reading) {
this.theme = theme;
this.author = author;
this.content = content;
this.reading = reading;
}
@Override
public String toString() {
return "ArticleDTO{" +
"theme='" + theme + '\'' +
", author='" + author + '\'' +
", content='" + content + '\'' +
", reading=" + reading +
'}';
}
}
定義4:測試類,例項化兩個微信使用者Kate和Sam,並註冊關注微信公眾號,當微信公眾號釋出訊息的時候,會通知所有的關注者。
public class Test {
public static void main(String[] args){
Observable obserable=new AccountOfficalSubject();
obserable.registerObserver(new WeChartObserver("Kate"));
obserable.registerObserver(new WeChartObserver("Sam"));
ArticleDTO articleDTO=new ArticleDTO("錢塘江大潮來襲","杭州之聲","每年8月18,錢塘江大潮最壯觀……",15L);
obserable.notifyObservers(articleDTO);
}
}
測試5.測試結果
4.總結-觀察者模式特點及適用場景
觀察者模式特點:
(1) 觀察者和被觀察者使用介面方式進行邏輯解耦,兩者之間耦合度較低,分離了訊息生成層(被觀察者)和訊息響應層(觀察者),兩方業務相互獨立,無論哪一方有變化,都不會影響另一方,有利於進行擴充套件。
(2) 重點在於被觀察者的實現,需要定義儲存觀察者引用的方法和通知觀察者釋出資訊的方法。
(3) 觀察者需要定義接收通知訊息的方法update即可。
適用場景:
(1)訊息的釋出訂閱,事件監聽,廣播通訊。
(2)對一個物件狀態的更新,需要其他物件同步更新,而且其他物件的數量動態可變。
(3)物件僅需要將自己的更新通知給其他物件而不需要知道其他物件的細節。