Java描述设计模式(11):观察者模式
本文源碼:GitHub·點這里 || GitEE·點這里
一、觀察者模式
1、概念描述
觀察者模式是對象的行為模式,又叫發(fā)布-訂閱(Publish/Subscribe)模式。觀察者模式定義了一種一對多的依賴關(guān)系,讓多個觀察者對象同時監(jiān)聽某一個主題對象,主題對象在狀態(tài)發(fā)生變化時,會通知所有觀察者對象。Redis和常用消息中間件的發(fā)布訂閱模式,都是基于該原理實現(xiàn)。
2、核心角色
- 抽象主題角色
抽象主題角色把所有對觀察者對象的統(tǒng)一聚集管理,每個主題都可以有一個或多個觀察者。抽象主題提供一個接口,可以增加和刪除觀察者對象,抽象主題角色又叫做抽象被觀察者(Observable)角色。
- 具體主題角色
將有關(guān)狀態(tài)存入具體觀察者對象;在具體主題的內(nèi)部狀態(tài)改變時,給所有登記過的觀察者發(fā)出通知。具體主題角色又叫做具體被觀察者角色。
- 抽象觀察者角色
為所有的具體觀察者定義一個接口,在得到主題的通知時更新自己,這個接口叫做更新接口。
- 具體觀察者角色
具體觀察者角色實現(xiàn)抽象觀察者角色所要求的更新接口,以便使本身的狀態(tài)與主題的狀態(tài)協(xié)調(diào)同步。如果需要,具體觀察者角色可以保持一個指向具體主題對象的引用。
3、源代碼實現(xiàn)
- 基于消息推送模式
主題對象向觀察者推送主題的消息,不管觀察者是否需要。
/*** 觀察者設(shè)計模式*/ public class C01_Observer {public static void main(String[] args) {// 創(chuàng)建主題對象ConcreteSubject subject = new ConcreteSubject();// 創(chuàng)建觀察者對象Observer observer1 = new ConcreteObserver("觀察者A");Observer observer2 = new ConcreteObserver("觀察者B");// 注冊觀察者subject.attach(observer1);subject.attach(observer2);// 修改主題狀態(tài)subject.change("New State !");/*** 主題狀態(tài):New State !*【觀察者A】狀態(tài):New State !*【觀察者B】狀態(tài):New State !*/} } // 抽象主題角色 abstract class Subject {// 保存注冊的觀察者對象private List<Observer> list = new ArrayList<>();/*** 注冊觀察者對象*/public void attach (Observer observer){list.add(observer);System.out.println("注冊一個觀察者:"+observer.getClass().getName());}/*** 刪除觀察者對象*/public void delete (Observer observer){list.remove(observer);System.out.println("刪除一個觀察者:"+observer);}/*** 通知所有注冊的觀察者對象*/public void notifyObserver (String newState){for (Observer observer : list) {observer.update(newState);}} } // 具體主題角色 class ConcreteSubject extends Subject{private String state ;public String getState (){return state ;}public void change (String newState){state = newState;System.out.println("主題狀態(tài):"+state);//狀態(tài)發(fā)生改變,通知各個觀察者this.notifyObserver(state);} } // 抽象觀察者角色 interface Observer {/*** 更新接口*/void update (String state); } // 具體觀察者角色 class ConcreteObserver implements Observer{private String name ;// 觀察者狀態(tài)private String observerState ;public ConcreteObserver (String name){this.name = name ;}/*** 更新觀察者的狀態(tài),使其與目標(biāo)的狀態(tài)保持一致*/@Overridepublic void update(String state) {observerState = state ;System.out.println("【"+this.name+"】狀態(tài):"+observerState);} }- 基于消息拉取模式
主題對象在通知觀察者的時候,傳遞少量信息。如果觀察者需要該消息內(nèi)容,由觀察者主動到主題對象中獲取,相當(dāng)于是觀察者從主題對象中拉數(shù)據(jù)。
該案例基于上述案例修改,觀察者獲取主題對象的消息話題,只有自己感興趣的話題,才進(jìn)一步獲取內(nèi)容。
public class C02_Observer_Pull {public static void main(String[] args) {// 創(chuàng)建主題對象ConcreteSubject1 subject = new ConcreteSubject1();// 創(chuàng)建觀察者對象Observer1 observer1 = new ConcreteObserver1("觀察者A","JAVA");Observer1 observer2 = new ConcreteObserver1("觀察者B","MySQL");// 注冊觀察者subject.attach(observer1);subject.attach(observer2);/** 修改主題狀態(tài)* 主題狀態(tài):JAVA State !* 【觀察者A】狀態(tài):JAVA State !* 主題狀態(tài):MySQL State !* 【觀察者B】狀態(tài):MySQL State !*/subject.change("JAVA State !","JAVA");subject.change("MySQL State !","MySQL");} } abstract class Subject1 {// 保存注冊的觀察者對象private List<Observer1> list = new ArrayList<>();/*** 注冊觀察者對象*/public void attach (Observer1 observer){list.add(observer);}/*** 刪除觀察者對象*/public void delete (Observer1 observer){list.remove(observer);System.out.println("刪除一個觀察者:"+observer);}/*** 通知所有注冊的觀察者對象,傳入消息的話題*/public void notifyObservers (String msgTopic){for (Observer1 observer : list){observer.update(this);}} } class ConcreteSubject1 extends Subject1 {private String state ;private String msgTopic ;public String getState (){return state ;}public String getMsgTopic (){return msgTopic ;}public void change (String newState,String newMsgTopic){this.state = newState ;this.msgTopic = newMsgTopic ;System.out.println("主題狀態(tài):"+state);this.notifyObservers(msgTopic);} }interface Observer1 {/*** 更新接口* @param subject 傳入主題對象,方面獲取相應(yīng)的主題對象的狀態(tài)*/void update(Subject1 subject); } class ConcreteObserver1 implements Observer1{private String name ;// 選擇話題private String msgTopic ;// 觀察者狀態(tài)private String observerState ;public ConcreteObserver1 (String name,String msgTopic){this.name = name ;this.msgTopic = msgTopic ;}@Overridepublic void update(Subject1 subject) {ConcreteSubject1 concreteSubject1 = (ConcreteSubject1)subject ;// 只有指定話題才拉取消息if (concreteSubject1.getMsgTopic().equals(msgTopic)){observerState = concreteSubject1.getState();System.out.println("【"+this.name+"】狀態(tài):"+observerState);}} }4、兩種模式比較
推模式是假定主題對象知道觀察者需要的數(shù)據(jù),直接推送,使得觀察者對象難以復(fù)用;而拉模式是主題對象不知道觀察者具體需要什么數(shù)據(jù),將把自身傳遞給觀察者,按需要取值。
二、JDK中應(yīng)用
JAVA語言的java.utill類庫里面,提供了一個Observable類以及一個Observer接口,構(gòu)成JAVA語言對觀察者模式的支持。
1、Observer接口
這個接口只定義了一個方法,即update()方法,當(dāng)被觀察者對象的狀態(tài)發(fā)生變化時,被觀察者對象的notifyObservers()方法就會調(diào)用這一方法。
package java.util; /*** A class can implement the <code>Observer</code> interface when it* wants to be informed of changes in observable objects. */ public interface Observer {/*** This method is called whenever the observed object is changed. An* application calls an <tt>Observable</tt> object's*/void update(Observable o, Object arg); }2、Observable類
被觀察者類都是java.util.Observable類的子類。java.util.Observable提供方法支持觀察者對象。
- setChanged方法:觀察者對象的狀態(tài)發(fā)生了變化。
- notifyObservers:調(diào)用所有登記過的觀察者對象的update()方法。
3、應(yīng)用案例
public class C03_Observer_JDK {public static void main(String[] args) {//創(chuàng)建被觀察者對象MsgSource msgSource = new MsgSource();//創(chuàng)建觀察者對象,并將被觀察者對象登記MsgConsumer watcher = new MsgConsumer(msgSource);msgSource.setData("Hello,Java");msgSource.setData("Bye Java");} } class MsgSource extends Observable {private String data = "";public String getData() {return data;}public void setData(String data) {if(!this.data.equals(data)){this.data = data;setChanged();}notifyObservers();} } class MsgConsumer implements java.util.Observer {// 添加觀察者public MsgConsumer(Observable msgSource){msgSource.addObserver(this);}// 狀態(tài)獲取@Overridepublic void update(Observable o, Object arg) {System.out.println("消息內(nèi)容:" + ((MsgSource)o).getData());} }三、優(yōu)缺點總結(jié)
觀察者模式的主要的作用是對象解耦,將觀察者和被觀察者隔離。
程序中包括多個被觀察者和多個被觀察者,開發(fā)和調(diào)試比較復(fù)雜,而且Java中的消息的通知默認(rèn)是順序執(zhí)行的,一個觀察者的執(zhí)行阻塞會影響整體的執(zhí)行效率。
四、源代碼地址
GitHub·地址 https://github.com/cicadasmile/model-arithmetic-parent GitEE·地址 https://gitee.com/cicadasmile/model-arithmetic-parent總結(jié)
以上是生活随笔為你收集整理的Java描述设计模式(11):观察者模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 蓝桥杯-算法训练 2的次幂表示
- 下一篇: FireBug 调试JS入门 —如何调试