Java設計模式之觀察者模式

來源:互聯網
上載者:User

標籤:

觀察者模式是定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴它的對象都得到通知並被自動更新。這一模式中的關鍵對象是目標(Subject)和觀察者(Obserber)。一個目標可以有任意個觀察者,一旦目標狀態發生改變,所有的觀察者將得到通知。這種互動也稱為發布-訂閱

觀察者模式的適用情境:

當一個抽象模型有兩個方面,其中一個方面依賴於另一個方面。將這二者封裝在獨立的對象中以使它們可以各自獨立地改變和複用。

當對一個對象的改變需要同時改變其它對象,而不知道具體有多少對象有待改變。

當一個對象必須通知其他對象,而它又不能假定其他對象是誰。換言之,你不希望這些對象是緊密耦合的。

基本結構:

Subject<---------ConcreteSubject

Observer<----------ConcreteObserver

Subject(目標):目標知道它的觀察者,可以有任意個觀察者;提供attach()、detach()、notifyObservers()方法介面。

ConcreteSubject(具體目標):寫入具體目標對象的狀態或內容(getter and setter方法),並且在它們的狀態發生改變時會向它的觀察者發出通知。

Observer(觀察者):定義目標發生改變時需獲得通知的對象定義一個介面,Update()方法。

?ConcreteObserver(具體觀察者):?維護一個指向ConcreteSubject對象的引用;儲存觀察者自身的狀態,實現Observer介面使自身狀態與目標狀態保持一致。

觀察者模式允許獨立的改變目標和觀察者。可以單獨複用目標對象而無需同時複用其觀察者,反之亦然。

觀察者模式的優點:目標與觀察者之間的抽象耦合,耦合與抽象達到最小;支援廣播更新。

觀察者模式的缺點:容易引起誤廣播,即其中一個觀察者修改了目標的狀態,則其他觀察者也收到了該更新。

觀察者模式的實現需要考慮以下幾個關鍵點:1.建立目標到其觀察者之間的映射;2.觀察多個目標;3.誰觸發更新;4.對已刪除目標的懸掛引用;5.在發出通知之前一定要確保目標的狀態自身是一致的;6.避免特定於觀察者的更新協議——推/拉模型:推模型是指目標向觀察者發送關於改變的詳細資料,而不管他們需要與否。拉模型是指目標除最小通知外什麼也不送出,而此後由觀察者顯示地向目標詢問細節。7.顯示地指定感興趣的改變。即可以讓觀察者對感興趣的目標才接受通知。


下面通過一段代碼來示範一下觀察者模式的應用案例:

Subject.java

package com.observer.classic;import java.util.ArrayList;import java.util.List;/** * 觀察者模式 * 目標對象 * @author zzw */public class Subject {//不同興趣點觀察者線性列表private List<Observer> observersAll = new ArrayList<Observer>();private List<Observer> observersMusic = new ArrayList<Observer>();private List<Observer> observersSport = new ArrayList<Observer>();private List<Observer> observersMovie = new ArrayList<Observer>();//增加觀察者public void attach(Observer observer) {String interest = observer.getObserverInterest();if("All".equals(interest)) {observersAll.add(observer);} else if("Music".equals(interest)) {observersMusic.add(observer);} else if("Sport".equals(interest)) {observersSport.add(observer);} else if("Movie".equals(interest)) {observersMovie.add(observer);}}//刪除觀察者public void detach(Observer observer) {String interest = observer.getObserverInterest();if("All".equals(interest)) {observersAll.remove(observer);} else if("Music".equals(interest)) {observersMusic.remove(observer);} else if("Sport".equals(interest)) {observersSport.remove(observer);} else if("Movie".equals(interest)) {observersMovie.remove(observer);}}public void notifyObservers(String subjectTag) {if("Music".equals(subjectTag)) {for(Observer observer : observersMusic) {observer.update(this);}} else if("Sport".equals(subjectTag)) {for(Observer observer : observersSport) {observer.update(this);}} else if("Movie".equals(subjectTag)) {for(Observer observer : observersMovie) {observer.update(this);}}for(Observer observer : observersAll) {observer.update(this);}}}


Observer.java

package com.observer.classic;/** * 觀察者介面 * @author zzw * */public interface Observer {public void update(Subject subject);public String getObserverInterest();}

ConcreteSubject.java

package com.observer.classic;/** * 具體的目標對象 * 負責把目標的狀態資訊存入到相應的觀察者身上 * @author zzw */public class ConcreteSubject extends Subject {//相應目標的狀態(內容)private String subjectState;//目標式通知的分類標籤private String subjectTag;public String getSubjectTag() {return subjectTag;}public String getSubjectState() {return subjectState;}public void setSubjectState(String subjectState,String subjectTag) {this.subjectState = subjectState;this.subjectTag = subjectTag;this.notifyObservers(subjectTag);}}

ConcreteObserver.java

package com.observer.classic;public class ConcreteObserver implements Observer {//觀察者姓名private String observerName;//觀察者興趣點private String observerInterest;//觀察者狀態資訊private String observerState;public String getObserverName() {return observerName;}public void setObserverName(String observerName) {this.observerName = observerName;}public String getObserverState() {return this.observerState;}public String getObserverInterest() {return observerInterest;}public void setObserverInterest(String observerInterest) {this.observerInterest = observerInterest;}@Overridepublic void update(Subject subject) {//擷取目標狀態,以保持更新observerState = ((ConcreteSubject) subject).getSubjectState();System.out.println(observerName + "收到了一條通知:" + observerState);}}


Test.java

package com.observer.classic;public class Test {public static void main(String[] args) {// 建立推送內容1ConcreteSubject concreteSubject = new ConcreteSubject();// 建立觀察者(即待通知對象)ConcreteObserver concreteObserver1 = new ConcreteObserver();concreteObserver1.setObserverName("張三");concreteObserver1.setObserverInterest("All");ConcreteObserver concreteObserver2 = new ConcreteObserver();concreteObserver2.setObserverName("李四");concreteObserver2.setObserverInterest("Music");ConcreteObserver concreteObserver3 = new ConcreteObserver();concreteObserver3.setObserverName("王二麻子");concreteObserver3.setObserverInterest("Sport");ConcreteObserver concreteObserver4 = new ConcreteObserver();concreteObserver4.setObserverName("劉老五");concreteObserver4.setObserverInterest("Movie");//註冊觀察者concreteSubject.attach(concreteObserver1);concreteSubject.attach(concreteObserver2);concreteSubject.attach(concreteObserver3);concreteSubject.attach(concreteObserver4);//發布通知1System.out.println("訊息一:");concreteSubject.setSubjectState("周杰倫發了一張新專輯《哎喲,不錯哦》","Music");//發布通知2System.out.println("訊息二:");concreteSubject.setSubjectState("姚明宣布退役了","Sport");//發布通知3System.out.println("訊息三:");concreteSubject.setSubjectState("新電影《梔子花開》上映了","Movie");}}

運行結果

訊息一:

李四收到了一條通知:周杰倫發了一張新專輯《哎喲,不錯哦》

張三收到了一條通知:周杰倫發了一張新專輯《哎喲,不錯哦》

訊息二:

王二麻子收到了一條通知:姚明宣布退役了

張三收到了一條通知:姚明宣布退役了

訊息三:

劉老五收到了一條通知:新電影《梔子花開》上映了

張三收到了一條通知:新電影《梔子花開》上映了


下面使用另外一種方法來實現有區分的觀察者,即把notifyObservers方法交由子類去實現,而父類僅僅提供抽象方法。

WeatherSubject.java

package com.observer.advanced;/** * 觀察者模式的進階 * 允許推送內容到特定的觀察者 * notifyObservers()在子類中實現 */import java.util.ArrayList;import java.util.List;public abstract class WeatherSubject {List<Observer> observers = new ArrayList<Observer>();public void attach(Observer observer) {observers.add(observer);}public void detach(Observer observer) {observers.remove(observer);}//留到子類中去實現protected abstract void notifyObservers();}

ConcreteWeatherSubject.java

package com.observer.advanced;public class ConcreteWeatherSubject extends WeatherSubject {//目標狀態private String subjectState;public ConcreteWeatherSubject(String subjectState) {super();this.subjectState = subjectState;}public String getSubjectState() {return subjectState;}public void setSubjectState(String subjectState) {this.subjectState = subjectState;//一旦目標得到修改,所有的觀察者都會收到通知this.notifyObservers();}@Overrideprotected void notifyObservers() {/** * 由於張三隻接受下雪的天氣預報,李四隻接受下雨的天氣預報,其他觀察者無限制 */for(Observer observer : observers) {if("下雪".equals(subjectState)) {if("張三".equals(observer.getObserverName()))observer.update(this);else if(!"李四".equals(observer.getObserverName()))observer.update(this);}else if("下雨".equals(subjectState)) {if("李四".equals(observer.getObserverName()))observer.update(this);else if(!"張三".equals(observer.getObserverName()))observer.update(this);}elseif(!"李四".equals(observer.getObserverName())&&!"張三".equals(observer.getObserverName()))observer.update(this);}}}

Observer.java

package com.observer.advanced;public interface Observer {public void update(WeatherSubject subject);//設定觀察者名稱public String getObserverName();public void setObserverName(String observerName);public String getObserverSex();public void setObserverSex(String observerSex);public String getObserverAge();public void setObserverAge(String observerAge);}

ConcreteObserver.java

package com.observer.advanced;public class ConcreteObserver implements Observer {private String observerName;private String observerSex;private String observerAge;public ConcreteObserver(String observerName, String observerSex,String observerAge) {super();this.observerName = observerName;this.observerSex = observerSex;this.observerAge = observerAge;}@Overridepublic void update(WeatherSubject subject) {// 推送內容String content = ((ConcreteWeatherSubject)subject).getSubjectState();System.out.println(this.getObserverName()+"("+this.getObserverSex()+","+this.getObserverAge()+")收到了一條訊息:"+content);}@Overridepublic String getObserverName() {return observerName;}@Overridepublic void setObserverName(String observerName) {this.observerName = observerName;}public String getObserverAge() {return observerAge;}public void setObserverAge(String observerAge) {this.observerAge = observerAge;}public String getObserverSex() {return observerSex;}public void setObserverSex(String observerSex) {this.observerSex = observerSex;}}

Test.java

package com.observer.advanced;public class Test {public static void main(String[] args) {//建立三個觀察者Observer concreteObserver1 = new ConcreteObserver("張三", "男", "22歲");Observer concreteObserver2 = new ConcreteObserver("李四", "男", "30歲");Observer concreteObserver3 = new ConcreteObserver("瑪麗", "女", "25歲");//建立目標內容:下雪WeatherSubject concreteWeatherSubject1 = new ConcreteWeatherSubject("下雪");concreteWeatherSubject1.attach(concreteObserver1);concreteWeatherSubject1.attach(concreteObserver2);concreteWeatherSubject1.attach(concreteObserver3);concreteWeatherSubject1.notifyObservers();//建立目標內容:下雨WeatherSubject concreteWeatherSubject2 = new ConcreteWeatherSubject("下雨");concreteWeatherSubject2.attach(concreteObserver1);concreteWeatherSubject2.attach(concreteObserver2);concreteWeatherSubject2.attach(concreteObserver3);concreteWeatherSubject2.notifyObservers();//建立目標內容:晴天WeatherSubject concreteWeatherSubject3 = new ConcreteWeatherSubject("晴天");concreteWeatherSubject3.attach(concreteObserver1);concreteWeatherSubject3.attach(concreteObserver2);concreteWeatherSubject3.attach(concreteObserver3);concreteWeatherSubject3.notifyObservers();}}


運行結果:

張三(男,22歲)收到了一條訊息:下雪

瑪麗(女,25歲)收到了一條訊息:下雪

李四(男,30歲)收到了一條訊息:下雨

瑪麗(女,25歲)收到了一條訊息:下雨

瑪麗(女,25歲)收到了一條訊息:晴天


Java設計模式之觀察者模式

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.