一、觀察者模式
當(dāng)對(duì)象中存在一對(duì)多的關(guān)系時(shí),就需要使用這種模式。比如說(shuō)一個(gè)對(duì)象發(fā)生改變時(shí),會(huì)通知到依賴(lài)它的對(duì)象。
介紹
- 意圖:定義對(duì)象之間一對(duì)多的依賴(lài)關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),會(huì)通知到其它依賴(lài)該對(duì)象的行為。
- 主要解決:一個(gè)對(duì)象狀態(tài)改變給其他對(duì)象通知的問(wèn)題,而且要考慮到易用和低耦合,保證高度的協(xié)作。
- 如何解決:采用面向?qū)ο蟮募夹g(shù),可以將這種關(guān)系弱化。
- 關(guān)鍵代碼:在被訂閱類(lèi)里面采用一個(gè)集合來(lái)存放觀察者,并且在狀態(tài)改變時(shí)一一通知他們?nèi)ジ隆?/li>
- 應(yīng)用實(shí)例:1.對(duì)于在訂閱了微信公眾號(hào)某個(gè)主題的用戶來(lái)說(shuō),每當(dāng)公眾號(hào)有發(fā)布新的內(nèi)容時(shí),會(huì)自動(dòng)的將內(nèi)容及時(shí)推送到用戶;2.在初中的教室上課,當(dāng)下課鈴聲響起的時(shí)候,學(xué)生們會(huì)主動(dòng)收拾書(shū)包準(zhǔn)備下課回家吃飯了;3.在某會(huì)議上面,領(lǐng)導(dǎo)召集了負(fù)責(zé)各個(gè)業(yè)務(wù)模塊的子領(lǐng)導(dǎo),及時(shí)傳達(dá)了某些核心思想,參與了此次會(huì)議的小負(fù)責(zé)人會(huì)通知到各個(gè)下屬。
- 注意事項(xiàng):1.Java中已經(jīng)有了對(duì)于觀察者的支持類(lèi)。2.避免循環(huán)引用。3.如果順序執(zhí)行,某一個(gè)觀察者執(zhí)行時(shí)發(fā)生了錯(cuò)誤,會(huì)導(dǎo)致卡克,一般采取異步的方式去執(zhí)行。
演示
下面通過(guò)一個(gè)小的demo來(lái)展示一下觀察者模式的使用場(chǎng)景。
-
微信公眾號(hào)推送文章
首先先來(lái)明確下各個(gè)扮演的角色,對(duì)于訂閱了某個(gè)公眾號(hào)的用戶來(lái)說(shuō),他們屬于觀察者,而公眾號(hào)的文章的發(fā)布屬于被觀察者。明確了這一點(diǎn)后,下面就比較好擼代碼了。
1、定義被觀察者的主要方法,采取接口來(lái)定義/** * 微信主題的接口 即被觀察著 他會(huì)有三個(gè)方法 * @author rain * */ public interface IWxServerSubject { void attach(IObserver observer); void detach(IObserver observer); void updateObserver(); }
2 、定義抽象的觀察者接口
/**
* 觀察者 訂閱了微信主題的觀察者
* @author rain
*
*/
public interface IObserver {
void receiveContent(String info);
}
`3、實(shí)現(xiàn)具體的被觀察者
public class IWxSubjectImpl implements IWxServerSubject{
//觀察者列表 訂閱了微信公眾號(hào)的讀者
private List<IObserver> observers = new ArrayList<>();
private String submitContent;
@Override
public void attach(IObserver observer) {
observers.add(observer);
}
//一個(gè)信號(hào) 即發(fā)布了新的文章
public void submitContent(String content){
this.submitContent = content;
updateObserver();
}
@Override
public void detach(IObserver observer) {
if(observers.contains(observer)){
observers.remove(observer);
}
}
@Override
public void updateObserver() {
for (IObserver iObserver : observers) {
iObserver.receiveContent(submitContent);
}
}
}
4、定義一個(gè)具體的觀察者
/**
* 讀者 訂閱了微信公眾號(hào)的 觀察者
* @author rain
*
*/
public class ReaderObsever implements IObserver{
private String name;
public ReaderObsever(String name) {
this.name = name;
}
@Override
public void receiveContent(String info) {
System.out.println(name +" ,請(qǐng)注意:Rain發(fā)布了新的微信公眾號(hào)文章---"+info);
}
public String getName(){
return name;
}
}
5、來(lái)個(gè)測(cè)試類(lèi)模擬一下吧
public class Test {
public static void main(String[] args) {
IWxServerSubject subject = new IWxSubjectImpl();
//創(chuàng)建了四個(gè)讀者 并且都關(guān)注了該公眾號(hào)的 只有趙六沒(méi)有關(guān)注
ReaderObsever reader1 = new ReaderObsever("張三");
ReaderObsever reader2 = new ReaderObsever("李四");
ReaderObsever reader3 = new ReaderObsever("王五");
//訂閱了該公眾號(hào)的讀者 即觀察者角色
subject.attach(reader1);
subject.attach(reader2);
subject.attach(reader3);
//公眾號(hào)發(fā)布了文章了
((IWxSubjectImpl)subject).submitContent("觀察者設(shè)計(jì)模式開(kāi)始啦?。?!");
}
}
運(yùn)行一下:

模擬觀察者.png
可以看到,訂閱過(guò)該公眾號(hào)的用戶確實(shí)收到了新發(fā)布的文章,good。。。