Java設(shè)計(jì)模式之觀察者模式(Observer模式)
一、觀察者模式是什么?
當(dāng)對(duì)象間存在一對(duì)多關(guān)系時(shí),則使用觀察者模式(Observer Pattern)。當(dāng)一個(gè)對(duì)象被修改時(shí),則會(huì)自動(dòng)通知依賴它的對(duì)象。觀察者模式屬于行為型模式。
人話: 就像微信公眾號(hào)推送消息,訂閱的人能收到,沒(méi)訂閱的收不到,還可以取消/添加訂閱
二、模式分析
2.1 四個(gè)角色
- 抽象主題(抽象被觀察者角色):也就是一個(gè)抽象主題,它把所有對(duì)觀察者對(duì)象的引用保存在一個(gè)集合中,每個(gè)主題都可以有任意數(shù)量的觀察者。抽象主題提供一個(gè)接口,可以增加和刪除觀察者角色。一般用一個(gè)抽象類(lèi)和接口來(lái)實(shí)現(xiàn)。
- 抽象觀察者角色:為所有的具體觀察者定義一個(gè)接口,在得到主題通知時(shí)更新自己。
- 具體主題(具體被觀察者角色):也就是一個(gè)具體的主題,在集體主題的內(nèi)部狀態(tài)改變時(shí),所有登記過(guò)的觀察者發(fā)出通知。
- 具體觀察者角色:實(shí)現(xiàn)抽象觀察者角色所需要的更新接口,一邊使本身的狀態(tài)與制圖的狀態(tài)相協(xié)調(diào)。
2.2 案例
- 微信公眾號(hào)
1.抽象主題
public interface Subject {
/**
* 注冊(cè)觀察者
*/
void registerObserver(observer observer);
/**
* 移除觀察者
*/
void removeObserver(observer observer);
/**
* 通知觀察者
*/
void notifyObservers();
}
2.抽象觀察者角色
public interface observer {
/**
* 更新
*/
void update(String message);
}
3.具體主題
用Vector是線程同步的,比較安全,也可以使用ArrayList,是線程異步的,但不安全。
public class WechatServer implements Subject{
//注意到這個(gè)List集合的泛型參數(shù)為Observer接口,設(shè)計(jì)原則:面向接口編程而不是面向?qū)崿F(xiàn)編程
private Vector<observer> list;
private String message;
public WechatServer() {
list = new Vector<observer>();
}
@Override
public void registerObserver(observer observer) {
list.add(observer);
}
@Override
public void removeObserver(observer observer) {
if(!list.isEmpty())
list.remove(observer);
}
@Override
public void notifyObservers() {
for(int i = 0; i < list.size(); i++) {
observer oserver = list.get(i);
oserver.update(message);
}
}
public void setInfomation(String s) {
this.message = s;
System.out.println("微信服務(wù)更新消息: " + s);
//消息更新,通知所有觀察者
notifyObservers();
}
}
4.具體觀察者角色
public class User implements observer {
private String name;
private String message;
public User(String name) {
this.name = name;
}
@Override
public void update(String message) {
this.message = message;
read();
}
public void read() {
System.out.println(name + " 收到推送消息: " + message);
}
}
5.測(cè)試類(lèi)
public class Test {
public static void main(String[] args) {
//主題
WechatServer server = new WechatServer();
//觀察者
observer userZhang = new User("ZhangSan");
observer userLi = new User("LiSi");
observer userWang = new User("WangWu");
server.registerObserver(userZhang);
server.setInfomation("C是世界上最好用的語(yǔ)言!");
System.out.println("====================================");
server.registerObserver(userLi);
server.registerObserver(userWang);
server.setInfomation("JAVA是世界上最好用的語(yǔ)言!");
}
}
6.結(jié)果

三、觀察者模式的優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
解除耦合,讓耦合的雙方都依賴于抽象,從而使得各自的變換都不會(huì)影響另一邊的變換。
缺點(diǎn)
在應(yīng)用觀察者模式時(shí)需要考慮一下開(kāi)發(fā)效率和運(yùn)行效率的問(wèn)題,程序中包括一個(gè)被觀察者、多個(gè)觀察者,開(kāi)發(fā)、調(diào)試等內(nèi)容會(huì)比較復(fù)雜,而且在Java中消息的通知一般是順序執(zhí)行,那么一個(gè)觀察者卡頓,會(huì)影響整體的執(zhí)行效率,在這種情況下,一般會(huì)采用異步實(shí)現(xiàn)。
四、總結(jié)
當(dāng)一個(gè)對(duì)象的改變需要同時(shí)改變其它對(duì)象,并且它不知道具體有多少對(duì)象有待改變的時(shí)候,應(yīng)該考慮使用觀察者模式。 而使用觀察者模式的動(dòng)機(jī)在于:將一個(gè)系統(tǒng)分割成一系列相互協(xié)作的類(lèi)有一個(gè)很不好的副作用,就是需要維護(hù)相關(guān)對(duì)象間的一致性,我們不希望為了維持一致性而使各類(lèi)緊密耦合,這樣會(huì)給維護(hù)、擴(kuò)展和重用都帶來(lái)不便,而觀察者模式所做的工作就是在解除耦合。
到此這篇關(guān)于Java設(shè)計(jì)模式之觀察者模式(Observer模式)的文章就介紹到這了,更多相關(guān)Java觀察者模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mybatis mapper接口動(dòng)態(tài)代理開(kāi)發(fā)步驟解析
這篇文章主要介紹了Mybatis mapper接口動(dòng)態(tài)代理開(kāi)發(fā)步驟解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07
JavaBean和Map轉(zhuǎn)換封裝類(lèi)的方法
下面小編就為大家?guī)?lái)一篇JavaBean和Map轉(zhuǎn)換封裝類(lèi)的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-10-10
Java靜態(tài)static與實(shí)例instance方法示例
這篇文章主要為大家介紹了Java靜態(tài)static與實(shí)例instance方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
Spring FreeMarker整合Struts2過(guò)程詳解
這篇文章主要介紹了Spring FreeMarker整合Struts2過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10
Java獲取某一日期的前N天(使用Calendar類(lèi))
這篇文章主要給大家介紹了關(guān)于Java如何使用Calendar類(lèi)獲取某一日期的前N天,我們可以使用Java中的Calendar類(lèi)來(lái)獲取前n天的時(shí)間,文中給出了詳細(xì)的代碼示例,需要的朋友可以參考下2023-08-08
RestTemplate 401 獲取錯(cuò)誤信息的處理方案
這篇文章主要介紹了RestTemplate 401 獲取錯(cuò)誤信息的處理方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
Java面向?qū)ο髮?shí)現(xiàn)汽車(chē)租賃系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了Java面向?qū)ο髮?shí)現(xiàn)汽車(chē)租賃系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02
SpringBoot2如何集成Elasticsearch6.x(TransportClient方式)
這篇文章主要介紹了SpringBoot2如何集成Elasticsearch6.x(TransportClient方式)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05

