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)實(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è)試類
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í)需要考慮一下開發(fā)效率和運(yùn)行效率的問(wèn)題,程序中包括一個(gè)被觀察者、多個(gè)觀察者,開發(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é)作的類有一個(gè)很不好的副作用,就是需要維護(hù)相關(guān)對(duì)象間的一致性,我們不希望為了維持一致性而使各類緊密耦合,這樣會(huì)給維護(hù)、擴(kuò)展和重用都帶來(lái)不便,而觀察者模式所做的工作就是在解除耦合。
到此這篇關(guān)于Java設(shè)計(jì)模式之觀察者模式(Observer模式)的文章就介紹到這了,更多相關(guān)Java觀察者模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JAVA初級(jí)項(xiàng)目——實(shí)現(xiàn)圖書管理系統(tǒng)
這篇文章主要介紹了JAVA如何實(shí)現(xiàn)圖書管理系統(tǒng),文中示例代碼非常詳細(xì),供大家參考和學(xué)習(xí),感興趣的朋友可以了解下2020-06-06Spring依賴注入中的@Resource與@Autowired詳解
這篇文章主要介紹了Spring依賴注入中的@Resource與@Autowired詳解,提到Spring依賴注入,大家最先想到應(yīng)該是@Resource和@Autowired,對(duì)于Spring為什么要支持兩個(gè)這么類似的注解卻未提到,屬于知其然而不知其所以然,本文就來(lái)做詳細(xì)講解,需要的朋友可以參考下2023-09-09關(guān)于Java錯(cuò)誤提示之找不到或無(wú)法加載主類的問(wèn)題及正確處理方法
當(dāng)我們?cè)诔鯇W(xué)Java的是時(shí)候,類文件中是不設(shè)定包名(package)的,這種情況下注意classpath,基本上沒(méi)有問(wèn)題,?本文主要說(shuō)明classpath和系統(tǒng)環(huán)境變量PATH都沒(méi)問(wèn)題的情況下出錯(cuò)原因和正確處理方法,感興趣的朋友一起看看吧2022-01-01java反射機(jī)制的一些學(xué)習(xí)心得小結(jié)
這篇文章主要給大家介紹了關(guān)于java反射機(jī)制的一些學(xué)習(xí)心得,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02JDK21無(wú)法導(dǎo)入TimeUnit類的解決辦法
這篇文章主要給大家介紹了關(guān)于JDK21無(wú)法導(dǎo)入TimeUnit類的解決辦法,TimeUnit是java.util.concurrent包下面的一個(gè)類,TimeUnit提供了可讀性更好的線程暫停操作,通常用來(lái)替換Thread.sleep(),需要的朋友可以參考下2024-01-01Spring Batch輕量級(jí)批處理框架實(shí)戰(zhàn)
本文主要介紹了Spring Batch輕量級(jí)批處理框架實(shí)戰(zhàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10Java基礎(chǔ)知識(shí)之BufferedReader流的使用
這篇文章主要介紹了Java基礎(chǔ)知識(shí)之BufferedReader流的使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12Java壓縮解壓zip技術(shù)_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
Java解壓縮zip - 多個(gè)文件(包括文件夾),對(duì)多個(gè)文件和文件夾進(jìn)行壓縮,對(duì)復(fù)雜的文件目錄進(jìn)行解壓。壓縮方法使用的是可變參數(shù),可以壓縮1到多個(gè)文件2017-05-05