Java設(shè)計(jì)模式之觀察者模式原理與用法詳解
本文實(shí)例講述了Java設(shè)計(jì)模式之觀察者模式原理與用法。分享給大家供大家參考,具體如下:
什么是觀察者模式
可以這么理解:
觀察者模式定義了一種一對多的依賴關(guān)系,讓多個觀察者對象同時(shí)監(jiān)聽某一個主題對象。
這個主題對象在狀態(tài)上發(fā)生變化時(shí),會通知所有觀察者對象,讓它們能夠自動更新自己。
也可以這樣理解:
觀察者模式是關(guān)于多個對象想知道一個對象中數(shù)據(jù)變化情況的一種成熟模式。觀察者模式中有一個稱作“主題”的對象和若干個稱作“觀察者”的對象,“主題”和“觀察者”之間是一種一對多的依賴關(guān)系。
當(dāng)“主題”的狀態(tài)發(fā)生變化時(shí),所有“觀察者”都得到通知。
日常生活中,最容易理解的例子就是微信公眾號。我們用微信訂閱的微信公共號就是這里所說的主題,而我們 每一個關(guān)注這個微信號的人就是這里的觀察者。公眾號每天有更新,所有訂閱者都會收到。
觀察者模式類圖:
應(yīng)用場景
一般被用來實(shí)現(xiàn)事件處理系統(tǒng)。
觀察者模式組成
從定義看,可以分成兩個角色, 觀察者和被觀察對象(即主題)
從類圖看,代碼實(shí)現(xiàn)有四個角色:
-
抽象主題角色: 把所有對觀察者對象的引用保存在一個集合中,每個抽象主題角色都可以有任意數(shù)量的觀察者。抽象主題提供一個接口,可以增加和刪除觀察者角色。一般用一個抽象類和接口來實(shí)現(xiàn)。
-
抽象觀察者角色:為所有具體的觀察者定義一個接口,在得到主題的通知時(shí)更新自己。
-
具體主題角色:在具體主題內(nèi)部狀態(tài)改變時(shí),給所有登記過的觀察者發(fā)出通知。具體主題角色通常用一個子類實(shí)現(xiàn)。
-
具體觀察者角色:該角色實(shí)現(xiàn)抽象觀察者角色所要求的更新接口,以便使本身的狀態(tài)與主題的狀態(tài)相協(xié)調(diào)。通常用一個子類實(shí)現(xiàn)。如果需要,具體觀察者角色可以保存一個指向具體主題角色的引用。
代碼實(shí)現(xiàn)觀察者模式
- 抽象主題角色
主題接口規(guī)定了具體主題需要實(shí)現(xiàn)的添加,刪除及通知觀察者更新數(shù)據(jù)的方法
/** * 抽象主題,被觀察者 * */ public interface Subject { /** * 添加觀察者 * * @param observer */ void addObserver(Observer observer); /** * 移除指定的觀察者 * * @param observer */ void removeObserver(Observer observer); /** * 移除所有的觀察者 */ void removeAll(); /** * data 是要通知給觀察者的數(shù)據(jù) 因?yàn)镺bject是所有類的父類,可以使用多態(tài),當(dāng)然 你也可以使用 泛型 * * @param data */ void notifyAllObserver(Object data); /** * 單獨(dú) 通知某一個觀察者 * * @param observer * @param data * data 是要通知給觀察者的數(shù)據(jù) 因?yàn)镺bject是所有類的父類,可以使用多態(tài),當(dāng)然 你也可以使用 泛型 */ void notify(Observer observer, Object data); }
- 抽象觀察者角色
觀察者接口規(guī)定了具體觀察者用來更新數(shù)據(jù)的方法
/** * 抽象觀察者接口 */ public interface Observer { /** * * @param subject 被觀察者 * @param data 被觀察者傳遞給觀察者的 數(shù)據(jù) */ void update(Subject subject,Object data); }
- 具體主題角色
public class ConcreteSubject implements Subject { //觀察者集合,用于管理所有的觀察者 List<Observer> mList = new ArrayList<>(); @Override public void addObserver(Observer observer) { // TODO Auto-generated method stub // 確保相同的觀察者只含有一個 if (observer == null) { throw new NullPointerException("observer == null"); } if (!mList.contains(observer)) { mList.add(observer); } } @Override public void removeObserver(Observer observer) { // TODO Auto-generated method stub mList.remove(observer); } @Override public void removeAll() { // TODO Auto-generated method stub mList.clear(); } @Override public void notifyAllObserver(Object data) { // TODO Auto-generated method stub for (Observer observer : mList) { observer.update(this, data); } } @Override public void notify(Observer observer, Object data) { // TODO Auto-generated method stub if (observer != null) { observer.update(this, data); } } }
- 具體的觀察者角色
這里我們可以定義多個具體的觀察者角色
觀察者One
public class ObserverOne implements Observer { @Override public void update(Subject subject, Object data) { // TODO Auto-generated method stub System.err .println("the messge from subject to-->" + this.getClass().getName() + "<---is " + data.toString()); } }
觀察者Two
public class ObserverTwo implements Observer { @Override public void update(Subject subject, Object data) { // TODO Auto-generated method stub System.err .println("the messge from subject to-->" + this.getClass().getName() + "<---is " + data.toString()); } }
觀察者Three
public class ObserverThree implements Observer { @Override public void update(Subject subject, Object data) { // TODO Auto-generated method stub System.err .println("the messge from subject to-->" + this.getClass().getName() + "<---is " + data.toString()); } }
- 測試類
public class TestObservePattern { public static void main(String[] args) { // TODO Auto-generated method stub ConcreteSubject concreteSubject = new ConcreteSubject(); ObserverOne observerOne=new ObserverOne(); ObserverTwo observerTwo=new ObserverTwo(); ObserverThree observerThree=new ObserverThree(); concreteSubject.addObserver(observerOne); concreteSubject.addObserver(observerTwo); concreteSubject.addObserver(observerThree); //通知所有的觀察者 concreteSubject.notifyAllObserver("wake up,wake up"); //通知某個特定的觀察者OberverTwo concreteSubject.notify(observerTwo, "Specila msg for you"); //觀察者ObserveThree 決定不再訂閱主題 concreteSubject.removeObserver(observerThree); //通知所有的觀察者 concreteSubject.notifyAllObserver("new Message come "); } }
更多java相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Java面向?qū)ο蟪绦蛟O(shè)計(jì)入門與進(jìn)階教程》、《Java數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Java操作DOM節(jié)點(diǎn)技巧總結(jié)》、《Java文件與目錄操作技巧匯總》和《Java緩存操作技巧匯總》
希望本文所述對大家java程序設(shè)計(jì)有所幫助。
相關(guān)文章
Java并發(fā)編程:CountDownLatch與CyclicBarrier和Semaphore的實(shí)例詳解
這篇文章主要介紹了Java并發(fā)編程:CountDownLatch與CyclicBarrier和Semaphore的實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-09-09Java二分查找算法與數(shù)組處理的應(yīng)用實(shí)例
二分查找法,又叫做折半查找法,它是一種效率較高的查找方法。數(shù)組對于每一門編程語言來說都是重要的數(shù)據(jù)結(jié)構(gòu)之一,當(dāng)然不同語言對數(shù)組的實(shí)現(xiàn)及處理也不盡相同。Java 語言中提供的數(shù)組是用來存儲固定大小的同類型元素2022-07-07Java經(jīng)典排序算法之歸并排序?qū)崿F(xiàn)代碼
這篇文章主要介紹了Java經(jīng)典排序算法之歸并排序?qū)崿F(xiàn)代碼,歸并排序是建立在歸并操作上的一種有效的排序算法,該算法是采用分治法的一個非常典型的應(yīng)用,將已有序的子序列合并,得到完全有序的序列,需要的朋友可以參考下2023-10-10Java中float類型的范圍及其與十六進(jìn)制的轉(zhuǎn)換例子
這篇文章主要介紹了Java中float類型的范圍及其與十六進(jìn)制的轉(zhuǎn)換例子,是Java入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-10-10Java中I/O流讀取數(shù)據(jù)不完整的問題解決
本文主要介紹了ava中I/O流讀取數(shù)據(jù)不完整的問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05spring啟動錯誤Singleton bean creation not al
本文主要介紹了spring啟動錯誤Singleton bean creation not allowed while the singletons of this factory are indestruction,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07springboot中RabbitMQ死信隊(duì)列的實(shí)現(xiàn)示例
死信隊(duì)列是一種特殊的消息隊(duì)列,用來存儲無法被正常消費(fèi)的消息,常被用來實(shí)現(xiàn)延遲處理,異常消息處理等,本文主要介紹了springboot中RabbitMQ死信隊(duì)列的實(shí)現(xiàn)示例,感興趣的可以了解一下2024-01-01舉例詳解用Java實(shí)現(xiàn)web分頁功能的方法
這篇文章主要介紹了舉例詳解用Java實(shí)現(xiàn)web分頁功能的方法,這種基本功能現(xiàn)一般通過Hibernate框架來完成,需要的朋友可以參考下2015-10-10Java工廠模式優(yōu)雅地創(chuàng)建對象以及提高代碼復(fù)用率和靈活性
Java工廠模式是一種創(chuàng)建型設(shè)計(jì)模式,通過定義一個工廠類來封裝對象的創(chuàng)建過程,將對象的創(chuàng)建和使用分離,提高代碼的可維護(hù)性和可擴(kuò)展性,同時(shí)可以實(shí)現(xiàn)更好的代碼復(fù)用和靈活性2023-05-05