1.觀察者模式簡(jiǎn)介
觀察者模式(Observer Pattern)是行為型(Behavioral)設(shè)計(jì)模式茧痒,定義了對(duì)象之間一對(duì)多的依賴關(guān)系带膜,當(dāng)一個(gè)對(duì)象發(fā)生狀態(tài)變更,所有的依賴對(duì)象都會(huì)被通知苍在。在觀察者模式中闻葵,發(fā)生變化的對(duì)象就是觀察目標(biāo)情龄,被通知的對(duì)象就是觀察者伐割,觀察目標(biāo)和觀察者是一對(duì)多的關(guān)系。
觀察者模式又被稱作發(fā)布/訂閱(Pub/Sub)模式刃唤。
觀察者模式一共有四種角色:
(1) Subject(主題):是觀察的目標(biāo)隔心,可以是接口或者抽象類,定義了增加尚胞、移除硬霍、通知觀察者的方法,還有自身操作的方法笼裳。
(2) ConcreteSubject(具體主題):具體主題是Subject的子類唯卖,內(nèi)部維護(hù)者具體有哪些觀察者;當(dāng)它的狀態(tài)發(fā)生改變時(shí)躬柬,向它的各個(gè)觀察者發(fā)出通知拜轨。有時(shí)候,Subject可以和ConcreteSubject合并成一個(gè)類允青。
(3)Observer(觀察者):觀察者將對(duì)觀察目標(biāo)的改變做出反應(yīng)橄碾,觀察者一般定義為接口,該接口聲明了更新數(shù)據(jù)的方法颠锉。
(4)ConcreteObserver(具體觀察者):具體觀察者實(shí)現(xiàn)抽象觀察者定義的方法法牲,完成具體的更新數(shù)據(jù)的動(dòng)作。
2. 觀察者模式舉例
下面舉個(gè)例子琼掠,當(dāng)股票股價(jià)小于10元或者大約20元時(shí)拒垃,向關(guān)注股票的股民(Investor)發(fā)送通知消息。
序號(hào) | 類名 | 角色 | 說明 |
---|---|---|---|
1 | Observer | Observer | 抽象觀察者 |
2 | Investor | ConcreteSubject | 股民類瓷蛙,具體觀察者角色 |
3 | Subject | Subject | 抽象主題悼瓮,是被觀察的對(duì)象 |
4 | Stock | ConcreteObserver | 股票類,具體主題角色 |
5 | ObserverMain | 客戶端 | 演示調(diào)用 |
1. 抽象觀察者
/**
* 抽象觀察者
*/
public interface Observer {
void update(String message);
}
2. 股民類艰猬,具體觀察者角色
/**
* 股民類横堡,具體觀察者角色
*/
public class Investor implements Observer {
private String name;
public Investor(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println("股民[" + name + "]收到了消息:" + message);
}
}
3.抽象主題,是被觀察的對(duì)象姥宝。
/**
* 抽象主題翅萤,是被觀察的對(duì)象。
*/
public interface Subject {
/**
* 增加觀察者
*
* @param observer
*/
void addObserver(Observer observer);
/**
* 刪除觀察者
*
* @param observer
*/
void deleteObserver(Observer observer);
/**
* 通知觀察者
*
* @param message 消息
*/
void notifyObservers(String message);
/**
* 模擬股票價(jià)格監(jiān)控
*
* @param price 股票價(jià)格
*/
void change(int price);
}
4.股票類腊满,具體主題角色
/**
* 股票類套么,具體主題角色
*/
public class Stock implements Subject {
private Vector<Observer> observers = new Vector<>();
/**
* 模擬股票價(jià)格監(jiān)控
*
* @param price 股票價(jià)格
*/
public void change(int price) {
if (price > 2000) {
notifyObservers("股票價(jià)格已經(jīng)超過20元。");
} else if (price < 1000) {
notifyObservers("股票價(jià)格已經(jīng)低于10元碳蛋。");
}
}
/**
* 增加觀察者
*
* @param observer
*/
@Override
public void addObserver(Observer observer) {
observers.add(observer);
}
/**
* 刪除觀察者
*
* @param observer
*/
@Override
public void deleteObserver(Observer observer) {
observers.remove(observer);
}
/**
* 通知觀察者
*
* @param message 消息
*/
@Override
public void notifyObservers(String message) {
Enumeration<Observer> enumeration = observers.elements();
while (enumeration.hasMoreElements()) {
Observer observer = enumeration.nextElement();
observer.update(message);
}
}
}
5.調(diào)用演示
public static void main(String[] args) {
// 創(chuàng)建觀察者對(duì)象
Observer observer1 = new Investor("張三");
Observer observer2 = new Investor("李四");
// 注冊(cè)觀察者對(duì)象
Subject stock = new Stock();
stock.addObserver(observer1);
stock.addObserver(observer2);
// stock 主題發(fā)生的變化胚泌,觀察者收到通知
stock.change(2100);
stock.change(900);
}
結(jié)果輸出:
股民[張三]收到了消息:股票價(jià)格已經(jīng)超過20元。
股民[李四]收到了消息:股票價(jià)格已經(jīng)超過20元肃弟。
股民[張三]收到了消息:股票價(jià)格已經(jīng)低于10元玷室。
股民[李四]收到了消息:股票價(jià)格已經(jīng)低于10元。
3. 總結(jié)
觀察者模式是一個(gè)使用頻率很高的設(shè)計(jì)模式笤受,為對(duì)象之間的行為聯(lián)動(dòng)提供了一套方案穷缤,簡(jiǎn)化了一對(duì)多的系統(tǒng)設(shè)計(jì)難度;需要注意的是箩兽,我們應(yīng)該避免觀察者和觀察目標(biāo)之間循環(huán)依賴津肛。
有的同學(xué)曾經(jīng)討論觀察者模式和“發(fā)布/訂閱”模式之間的區(qū)別,提出一種觀點(diǎn):在觀察者模式中汗贫,觀察目標(biāo)(本例中的Subject身坐、Stock)直接依賴觀察者(本例中的Observer);而“發(fā)布/訂閱”模式中落包,觀察目標(biāo)并不直接依賴于觀察者部蛇,而是通過中介媒介來通信。
在消息隊(duì)列中間件或者說JMS協(xié)議中咐蝇,Topic就是“發(fā)布/訂閱”的模式涯鲁,發(fā)布消息的生產(chǎn)者把消息送入Topic,消費(fèi)消息的消費(fèi)者訂閱這個(gè)Topic有序,從中消費(fèi)數(shù)據(jù)撮竿;生產(chǎn)者和消費(fèi)者互不依賴。
(完)