您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關(guān)JAVA的觀察者模式的作用是什么,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
當(dāng)對象間存在一對多關(guān)系時,則使用觀察者模式(Observer Pattern)。比如,當(dāng)一個對象被修改時,則會自動通知它的依賴對象。觀察者模式屬于行為型模式。觀察者模式是Java非常重要的一個設(shè)計模式。
觀察者模式所涉及的角色有:
● 抽象主題(Subject)角色:抽象主題角色把所有對觀察者對象的引用保存在一個聚集(比如ArrayList對象)里,每個主題都可以有任何數(shù)量的觀察者。抽象主題提供一個接口,可以增加和刪除觀察者對象,抽象主題角色又叫做抽象被觀察者(Observable)角色。
● 具體主題(ConcreteSubject)角色:將有關(guān)狀態(tài)存入具體觀察者對象;在具體主題的內(nèi)部狀態(tài)改變時,給所有登記過的觀察者發(fā)出通知。具體主題角色又叫做具體被觀察者(Concrete Observable)角色。
● 抽象觀察者(Observer)角色:為所有的具體觀察者定義一個接口,在得到主題的通知時更新自己,這個接口叫做更新接口。
● 具體觀察者(ConcreteObserver)角色:存儲與主題的狀態(tài)自恰的狀態(tài)。具體觀察者角色實現(xiàn)抽象觀察者角色所要求的更新接口,以便使本身的狀態(tài)與主題的狀態(tài) 像協(xié)調(diào)。如果需要,具體觀察者角色可以保持一個指向具體主題對象的引用。
抽象主題(subject)角色:
import java.util.ArrayList; import java.util.List; public abstract class Subject { private List<MyObserver>list = new ArrayList<>(); public void register(MyObserver myObserver){ if (!list.contains(myObserver)){ list.add(myObserver); } } public void remove(MyObserver myObserver){ if (list.contains(myObserver)){ list.remove(myObserver); } } public void notifyObserver(){ for (MyObserver myObserver : list) { myObserver.update(); } } }
抽象觀察者角色:
public interface MyObserver { void update(); }
具體主題角色:
public class Repoter extends Subject { private String msg; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; if (change()) { notifyObserver(); } } public Boolean change() { if (msg.equals(getMsg())) { return true; } else { return false; } } }
第一個具體觀察者對象:
public class PeopleDaily implements MyObserver { private Subject subject; public PeopleDaily(Subject subject) { this.subject = subject; subject.register(this); } @Override public void update() { System.out.println("人民日報發(fā)布最新報道:" + ((Repoter) subject).getMsg()); } public void remove() { subject.remove(this); } }
第二個具體觀察者對象:
public class NewsFeeds implements MyObserver { private Subject subject; public NewsFeeds(Subject subject) { this.subject = subject; subject.register(this); } @Override public void update() { System.out.println("新聞聯(lián)播發(fā)布最新報道:" + ((Repoter) subject).getMsg()); } public void remove() { subject.remove(this); } }
第三個具體觀察者對象:
public class XinHuaNewsAgency implements MyObserver { private Subject subject; public XinHuaNewsAgency(Subject subject) { this.subject = subject; subject.register(this); } @Override public void update() { System.out.println("新華社發(fā)布最新報道:" + ((Repoter) subject).getMsg()); } public void remove() { subject.remove(this); } }
測試:
public class TestDemo { @Test public void demo(){ Repoter repoter = new Repoter(); NewsFeeds newsFeeds = new NewsFeeds(repoter); XinHuaNewsAgency xinHuaNewsAgency = new XinHuaNewsAgency(repoter); PeopleDaily peopleDaily = new PeopleDaily(repoter); repoter.setMsg("為實現(xiàn)中華民族偉大復(fù)興而奮斗?。?!"); } }
結(jié)果:
新聞聯(lián)播發(fā)布最新報道:為實現(xiàn)中華民族偉大復(fù)興而奮斗!??! 新華社發(fā)布最新報道:為實現(xiàn)中華民族偉大復(fù)興而奮斗?。。? 人民日報發(fā)布最新報道:為實現(xiàn)中華民族偉大復(fù)興而奮斗?。?! Process finished with exit code 0
刪除一個觀察者再試:
public class TestDemo { @Test public void demo(){ Repoter repoter = new Repoter(); NewsFeeds newsFeeds = new NewsFeeds(repoter); XinHuaNewsAgency xinHuaNewsAgency = new XinHuaNewsAgency(repoter); PeopleDaily peopleDaily = new PeopleDaily(repoter); repoter.setMsg("為實現(xiàn)中華民族偉大復(fù)興而奮斗?。?!"); repoter.remove(xinHuaNewsAgency); System.out.println("————————————————————————————————————————————————"); repoter.setMsg("華為發(fā)布最新旗艦機Mate30系列型號手機"); } }
結(jié)果:
新聞聯(lián)播發(fā)布最新報道:為實現(xiàn)中華民族偉大復(fù)興而奮斗?。。? 新華社發(fā)布最新報道:為實現(xiàn)中華民族偉大復(fù)興而奮斗?。?! 人民日報發(fā)布最新報道:為實現(xiàn)中華民族偉大復(fù)興而奮斗?。。? ———————————————————————————————————————————————— 新聞聯(lián)播發(fā)布最新報道:華為發(fā)布最新旗艦機Mate30系列型號手機 人民日報發(fā)布最新報道:華為發(fā)布最新旗艦機Mate30系列型號手機 Process finished with exit code 0
對于觀察者模式,JDK已經(jīng)為我們提供了對應(yīng)的接口和類。
JDK源代碼:
package java.util; /** * * 當(dāng)一個類想要被告知可觀察對象的變化時,它可以實現(xiàn) Observer 接口。 * @author Chris Warth * @see java.util.Observable * @since JDK1.0 */ public interface Observer { /** * * 每當(dāng)觀察對象發(fā)生變化時,都會調(diào)用此方法。應(yīng)用程序調(diào)用 Observable 對象的 notifyObservers 方法,以便讓所有對 * 象的觀察者收到更改通知。 * @param o the observable object. * @param arg an argument passed to the <code>notifyObservers</code> * method. */ void update(Observable o, Object arg); }
Observer是一個接口,只是一個方法update用于接收通知者的通知并做出相應(yīng),具體的邏輯肯定是需要開發(fā)者自己實現(xiàn)的了。
被觀察者,JDK的源碼如下:
package java.util; /** * * 此類表示可觀察對象,或模型 - 視圖范例中的“數(shù)據(jù)”。它可以被子類化以表示應(yīng)用程序想要觀察的對象。 * 可觀察對象可以有一個或多個觀察者。觀察者可以是實現(xiàn)接口 Observer 的任何對象。 * 在可觀察的實例發(fā)生更改后,調(diào)用 Observable 的 notifyObservers 方法,應(yīng)用程序會通過調(diào)用 update 來通知所有觀察 * 者的更改。 * 未指定通知的遞送順序。 Observable類中提供的默認實現(xiàn)將按照它們注冊的順序通知Observers,但是子類可能會更改此順 * 序,使用不保證順序,在單獨的線程上發(fā)送通知,或者可以保證它們的子類遵循此順序,因為它們選擇。 * 請注意,此通知機制與線程無關(guān),并且與類 Object 的 wait 和 notify 機制完全分開。 * 當(dāng)新創(chuàng)建可觀察對象時,其觀察者集合為空。當(dāng)且僅當(dāng) equals 方法為它們返回true時,才認為兩個觀察者是相同的。 * @author Chris Warth * @see java.util.Observable#notifyObservers() * @see java.util.Observable#notifyObservers(java.lang.Object) * @see java.util.Observer * @see java.util.Observer#update(java.util.Observable, java.lang.Object) * @since JDK1.0 */ public class Observable { private boolean changed = false; private Vector<Observer> obs; //構(gòu)造方法 public Observable() { obs = new Vector<>(); } /** * 將觀察者添加到此對象的觀察者集中,前提是它與集合中已有的某個觀察者不同。未指定將通知發(fā)送給多個觀察者的順序。 * @param o an observer to be added. * @throws NullPointerException if the parameter o is null. */ public synchronized void addObserver(Observer o) { if (o == null) throw new NullPointerException(); if (!obs.contains(o)) { obs.addElement(o); } } /** * * 從該對象的觀察者集中刪除觀察者。將 null 傳遞給此方法將不起作用。 * @param o the observer to be deleted. */ public synchronized void deleteObserver(Observer o) { obs.removeElement(o); } /** * * 如果此對象已更改,如 hasChanged 方法所示,則通知其所有觀察者,然后調(diào)用 clearChanged 方法以指示此對象不再 * 更改。 * 每個觀察者都使用兩個參數(shù)調(diào)用 update 方法:observable對象和 null 。換句話說,此方法等效于: * notifyObservers(null) * @see java.util.Observable#clearChanged() * @see java.util.Observable#hasChanged() * @see java.util.Observer#update(java.util.Observable, java.lang.Object) */ public void notifyObservers() { notifyObservers(null); } /** * * 如果此對象已更改,如 hasChanged 方法所示,則通知其所有觀察者,然后調(diào)用 clearChanged 方法以指示此對象不再 * 更改。 * 每個觀察者都使用兩個參數(shù)調(diào)用 update 方法:observable對象和 arg 參數(shù)。 * @param arg any object. * @see java.util.Observable#clearChanged() * @see java.util.Observable#hasChanged() * @see java.util.Observer#update(java.util.Observable, java.lang.Object) */ public void notifyObservers(Object arg) { /* * * 臨時數(shù)組緩沖區(qū),用作當(dāng)前Observers狀態(tài)的快照。 */ Object[] arrLocal; synchronized (this) { /* * 我們不希望Observer在擁有自己的Monitor時進行任意代碼的回調(diào)。我們從Vector中提取每個Observable并存 * 儲Observer狀態(tài)的代碼需要同步,但是通知觀察者不會(不應(yīng)該)。這里任何潛在競爭條件的最壞結(jié)果是: * 1)新添加的觀察者將錯過正在進行的通知 * 2)最近未注冊的觀察者將被錯誤地通知 */ if (!changed) return; arrLocal = obs.toArray(); clearChanged(); } for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg); } /** * * 清除觀察者列表,以便此對象不再具有任何觀察者。 */ public synchronized void deleteObservers() { obs.removeAllElements(); } /** * * 將此 Observable 對象標記為已更改; hasChanged 方法現(xiàn)在將返回 true 。 */ protected synchronized void setChanged() { changed = true; } /** * * 表示此對象已不再更改,或者已向其所有觀察者通知其最近的更改,因此 hasChanged 方法現(xiàn)在將返回 false 。 * 此方法由 notifyObservers 方法自動調(diào)用。 * @see java.util.Observable#notifyObservers() * @see java.util.Observable#notifyObservers(java.lang.Object) */ protected synchronized void clearChanged() { changed = false; } /** * * 測試此對象是否已更改。 * @return <code>true</code> if and only if the <code>setChanged</code> * method has been called more recently than the * <code>clearChanged</code> method on this object; * <code>false</code> otherwise. * @see java.util.Observable#clearChanged() * @see java.util.Observable#setChanged() */ public synchronized boolean hasChanged() { return changed; } /** * * 返回此 Observable 對象的觀察者數(shù)。 * @return the number of observers of this object. */ public synchronized int countObservers() { return obs.size(); } }
Java源碼使用Vector,Vector相比于ArrayList來說,它是線程安全的。在添加和刪除觀察者時對兩個方法使用了synchronized關(guān)鍵字,這都是在為多線程考慮。
觀察者:實現(xiàn)觀察者接口(java.util.Observer),然后調(diào)用任何Observable對象的addObserver()方法,注銷觀察者時,就調(diào)用deleteObserver()方法即可。
第一個觀察者對象:
public class XinhuaNewsAgency implements Observer { //被觀察者對象 private Observable observable; public XinhuaNewsAgency(Observable observable) { this.observable = observable; //將觀察者對象加入到觀察者集合中 observable.addObserver(this); } @Override public void update(Observable o, Object arg) { if(o instanceof Repoter){ System.out.println("新華社發(fā)布最新報道:" + ((Repoter) o).getMsg()); } } public void remove(){ //刪除觀察者 observable.deleteObserver(this); } }
第二個觀察者對象:
public class PeopleDaily implements Observer { //被觀察者對象 private Observable observable; public PeopleDaily(Observable observable) { this.observable = observable; //將觀察者對象加入到觀察者集合中 observable.addObserver(this); } @Override public void update(Observable o, Object arg) { if (o instanceof Repoter){ System.out.println("人民日報發(fā)布最新報道:" + ((Repoter) o).getMsg()); } } public void remove(){ //刪除觀察者 observable.deleteObserver(this); } }
第三個觀察者對象:
public class NewsFeeds implements Observer { //被觀察對象 private Observable observable; public NewsFeeds(Observable observable) { this.observable = observable; //將觀察者對象加入到觀察者集合中 observable.addObserver(this); } @Override public void update(Observable o, Object arg) { if (o instanceof Repoter){ System.out.println("新聞聯(lián)播發(fā)布最新報道:" + ((Repoter) o).getMsg()); } } public void remove(){ //刪除觀察者 observable.deleteObserver(this); } }
被觀察者:繼承java.util.Observable類,調(diào)用setChanged()方法,標記狀態(tài)改變。然后調(diào)用nofityObservers()方法或者notifyobservers(Object arg) 方法。
public class Repoter extends Observable { private String msg; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; this.setChanged(); this.notifyObservers(msg); } }
測試:
public class TestDemo { @Test public void demo(){ Repoter repoter = new Repoter(); NewsFeeds newsFeeds = new NewsFeeds(repoter); PeopleDaily peopleDaily = new PeopleDaily(repoter); XinhuaNewsAgency xinhuaNewsAgency = new XinhuaNewsAgency(repoter); repoter.setMsg("為實現(xiàn)中華民族偉大復(fù)興而奮斗!?。?quot;); } }
結(jié)果:
新華社發(fā)布最新報道:為實現(xiàn)中華民族偉大復(fù)興而奮斗?。?! 人民日報發(fā)布最新報道:為實現(xiàn)中華民族偉大復(fù)興而奮斗!??! 新聞聯(lián)播發(fā)布最新報道:為實現(xiàn)中華民族偉大復(fù)興而奮斗!??! Process finished with exit code 0
結(jié)果發(fā)現(xiàn)順序和注冊的順序并不一致。將新聞聯(lián)播注銷,在運行:
public class TestDemo { @Test public void demo(){ Repoter repoter = new Repoter(); NewsFeeds newsFeeds = new NewsFeeds(repoter); PeopleDaily peopleDaily = new PeopleDaily(repoter); XinhuaNewsAgency xinhuaNewsAgency = new XinhuaNewsAgency(repoter); repoter.setMsg("為實現(xiàn)中華民族偉大復(fù)興而奮斗?。?!"); newsFeeds.remove(); System.out.println("————————————————————————————————————————————————"); repoter.setMsg("華為發(fā)布最新旗艦機Mate30系列型號手機"); } }
結(jié)果:
新華社發(fā)布最新報道:為實現(xiàn)中華民族偉大復(fù)興而奮斗?。?! 人民日報發(fā)布最新報道:為實現(xiàn)中華民族偉大復(fù)興而奮斗?。?! 新聞聯(lián)播發(fā)布最新報道:為實現(xiàn)中華民族偉大復(fù)興而奮斗?。?! ———————————————————————————————————————————————— 新華社發(fā)布最新報道:華為發(fā)布最新旗艦機Mate30系列型號手機 人民日報發(fā)布最新報道:華為發(fā)布最新旗艦機Mate30系列型號手機 Process finished with exit code 0
劣勢:
Observable是一個類,而不是一個接口,導(dǎo)致Observable類的擴展性不高,不如自己實現(xiàn)的觀察者模式靈活。
Observable將某些方法保護了起來(setChanged()和clearChanged()為protected),這意味著除非繼承自O(shè)bservable,否則將有關(guān)鍵的方法不能調(diào)用。導(dǎo)致無法通過組合的方式使其它類獲得Observable類的功能。
看完上述內(nèi)容,你們對JAVA的觀察者模式的作用是什么有進一步的了解嗎?如果還想了解更多知識或者相關(guān)內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。