摘要:時間年月日星期二說明本文部分內容均來自慕課網。慕課網教學源碼學習源碼第一章觀察者模式概述課程簡介觀察者模式的定義定義對象間的一種一對多的依賴關系。
時間:2017年08月29日星期二
說明:本文部分內容均來自慕課網。@慕課網:http://www.imooc.com
教學源碼:https://github.com/zccodere/s...
學習源碼:https://github.com/zccodere/s...
觀察者模式的定義
定義對象間的一種一對多的依賴關系。當一個對象的狀態發生改變時,所有依賴于它的對象都得到通知并被自動更新。
案例流程圖
第二章:觀察者模式實戰 2-1 結構類圖觀察者模式結構
觀察者模式類圖
2-2 通用代碼實現步驟
1.目標對象的定義 2.具體的目標對象的定義 3.觀察者的接口定義 4.觀察者的具體實現
代碼編寫
1.編寫Subject類
package com.myimooc.designpattern.c5observer.common; import java.util.ArrayList; import java.util.List; /** * @describe 目標類,目標對象,它知道觀察它的觀察者,并提供注冊(添加)和刪除觀察者的接口 * @author zc * @version 1.0 2017-08-29 */ public class Subject { /** * 用來保證注冊的觀察者對象 */ private Listobservers = new ArrayList (); /** * 增加觀察者 */ public void attach(Observer observer){ observers.add(observer); } /** * 刪除指定的觀察者 */ public void detach(Observer observer){ observers.remove(observer); } /** * 通過所有注冊的觀察者對象 */ protected void notifyObserver() { observers.forEach(observer ->{ observer.update(this); }); } }
2.編寫ConcreteSubject類
package com.myimooc.designpattern.c5observer.common; /** * @describe 具體的目標對象,負責把有關狀態存入到相應的觀察者對象中 * @author zc * @version 1.0 2017-08-29 */ public class ConcreteSubject extends Subject { /** * 目標對象的狀態 */ private String subjectState; public String getSubjectState() { return subjectState; } public void setSubjectState(String subjectState) { this.subjectState = subjectState; // 當狀態發生改變時,通知觀察者 this.notifyObserver(); } }
3.編寫Observer類
package com.myimooc.designpattern.c5observer.common; /** * @describe 觀察者接口,定義一個更新的接口給那些在目標對象發生改變的時候被通知的對象 * @author zc * @version 1.0 2017-08-29 */ public interface Observer { /** * 更新的接口 * @param subject 傳入的目標對象,方便獲取相應的目標對象的狀態 */ void update(Subject subject); }
4.編寫ConcreteObserver類
package com.myimooc.designpattern.c5observer.common; /** * @describe 具體的觀察者對象,實現更新的方法,使自身的狀態和目標的狀態保持一致 * @author zc * @version 1.0 2017-08-29 */ public class ConcreteObserver implements Observer { /** * 觀察者的狀態 */ private String observerState; /** * 獲取目標類的狀態同步到觀察者的狀態中 */ @Override public void update(Subject subject) { observerState = ((ConcreteSubject)subject).getSubjectState(); } public String getObserverState() { return observerState; } }2-3 訂閱天氣
代碼編寫
1.編寫WeatherSubject類
package com.myimooc.designpattern.c5observer.weather; import java.util.ArrayList; import java.util.List; /** * @describe 管理訂閱者列表 * @author zc * @version 1.0 2017-08-29 */ public class WeatherSubject { /** * 訂閱者列表 */ private Listobservers = new ArrayList (); /** * 把訂閱天氣的人增加到訂閱者列表中 */ public void attach(Observer observer){ observers.add(observer); } /** * 刪除訂閱的人 */ public void detach(Observer observer){ observers.remove(observer); } /** * 通知所有已經訂閱天氣的人 */ protected void notifyObserver() { observers.forEach(observer ->{ observer.update(this); }); } }
2.編寫ConcreteWeatherSubject類
package com.myimooc.designpattern.c5observer.weather; /** * @describe 具體的目標對象,負責把有關狀態存入到相應的觀察者對象中 * @author zc * @version 1.0 2017-08-29 */ public class ConcreteWeatherSubject extends WeatherSubject { /** * 獲取天氣的內容信息 */ private String weatherContent; public String getWeatherContent() { return weatherContent; } public void setWeatherContent(String weatherContent) { this.weatherContent = weatherContent; // 內容有了,說明天氣更新了,通知所有訂閱的人 this.notifyObserver(); } }
3.編寫Observer類
package com.myimooc.designpattern.c5observer.weather; /** * @describe 觀察者接口,定義一個更新的接口給那些在目標對象發生改變的時候被通知的對象 * @author zc * @version 1.0 2017-08-29 */ public interface Observer { /** * 更新的接口 * @param subject 傳入的目標對象,方便獲取相應的目標對象的狀態 */ void update(WeatherSubject subject); }
4.編寫ConcreteObserver類
package com.myimooc.designpattern.c5observer.weather; /** * @describe 具體的觀察者對象,實現更新的方法,使自身的狀態和目標的狀態保持一致 * @author zc * @version 1.0 2017-08-29 */ public class ConcreteObserver implements Observer { /** * 觀察者的名稱,是誰收到了這個信息 */ private String observerName; /** * 天氣的內容信息,這個消息從目標處獲取 */ private String weatherContent; /** * 提醒的內容,不同的觀察者提醒不同的內容 */ private String remindThing; /** * 獲取目標類的狀態同步到觀察者的狀態中 */ @Override public void update(WeatherSubject subject) { weatherContent = ((ConcreteWeatherSubject)subject).getWeatherContent(); System.out.println(observerName + " 收到了天氣信息 " + weatherContent + ",準備去做 "+remindThing); } public String getObserverName() { return observerName; } public void setObserverName(String observerName) { this.observerName = observerName; } public String getWeatherContent() { return weatherContent; } public void setWeatherContent(String weatherContent) { this.weatherContent = weatherContent; } public String getRemindThing() { return remindThing; } public void setRemindThing(String remindThing) { this.remindThing = remindThing; } }
5.編寫Client類
package com.myimooc.designpattern.c5observer.weather; /** * @describe 訂閱天氣-測試類 * @author zc * @version 1.0 2017-08-29 */ public class Client { public static void main(String[] args) { // 1.創建目標 ConcreteWeatherSubject weather = new ConcreteWeatherSubject(); // 2.創建觀察者 ConcreteObserver observerGiel = new ConcreteObserver(); observerGiel.setObserverName("黃明的女朋友"); observerGiel.setRemindThing("是我們的第一次約會,地點街心公園,不見不散哦"); ConcreteObserver observerMum = new ConcreteObserver(); observerMum.setObserverName("老媽"); observerMum.setRemindThing("是一個購物的好日子,明天去天虹掃貨"); // 3.注冊觀察者 weather.attach(observerGiel); weather.attach(observerMum); // 4.目標發布天氣 weather.setWeatherContent("明天 天氣晴朗,藍天白云,氣溫28℃"); } }第三章:觀察者模式詳解 3-1 深入認識
目標與觀察者之間的關系
一對多的關系 一對一的關系(如果觀察者只有一個)
單向依賴
在觀察者模式中,觀察者和目標是單向依賴,只有觀察者依賴目標,而不是目標依賴觀察者。主動權掌握在目標手中,只有目標知道什么時候需要通知觀察者。
命名建議
觀察者模式又被稱為發布訂閱模式 目標接口的定義,建議在名稱后面跟Subject 觀察者接口的定義,建議在名稱后面跟Observer 觀察者接口的更新方法,建議名稱為uodate
觸發通知的時機
一般情況下,是在完成了狀態維護后觸發。因為通知會傳遞數據,不能先通知,后改數據,這會導致觀察者和目標對象狀態不一致。
觀察者模式的調用順序示意圖-準備階段
運行階段
通知的順序
從理論上來說,當目標對象的狀態發生改變時,通知所有觀察者的時候,順序是不確定的。 因此,觀察者實現的功能,絕對不能依賴于通知的順序。 也就是說,多個觀察者之間的順序是平行的,相互不應該有先后依賴的關系。3-2 推拉模型
推模型
目標對象主動向觀察者推送目標的詳細信息 推送的信息通常是目標對象的全部或部分數據 相當于是在廣播通訊
拉模型(第二章的實現屬于拉模型)
目標對象在通知觀察者的時候,只傳遞少量信息 如果觀察者需要更具體的信息,由觀察者主動到目標對象中獲取 相當于是觀察者從目標對象中拉數據 一般這種模型的實現中,會把目標對象自身通過update方法傳遞給觀察者
兩種模型的區別
推模型是假定目標對象知道觀察者需要的數據 推模型會使觀察者對象難以復用 拉模型是目標對象不知道觀察者具體需要什么數據,因此把自身傳給觀察者,由觀察者來取值 拉模型下,update方法的參數是目標對象本身,基本上可以適應各種情況的需要3-3 Java實現
Java實現與自己實現的對比
不需要再定義觀察者和目標的接口了,JDK定義好了 具體的目標實現里面不需要再維護觀察者的注冊信息了,JDK在Observable類里面實現好了 觸發通知的方式有一點變化,要先調用setChanged方法,這是為了實現更精確的觸發控制 具體觀察者的實現里面,update方法能同時支持推模型和拉模型
代碼編寫
1.編寫ConcreteWeatherSubject類
package com.myimooc.designpattern.c5observer.weatherjdk; import java.util.Observable; /** * @describe 使用JDK實現觀察者模式,天氣目標具體實現類 * @author zc * @version 1.0 2017-08-29 */ public class ConcreteWeatherSubject extends Observable { /** 天氣情況的內容 */ private String content; public String getContent() { return content; } public void setContent(String content) { this.content = content; // 天氣情況有了,就要通知所有的觀察者 // 在用Java中的Observer模式時,需要先調用setChanged方法 this.setChanged(); // 調用通知方法-推模型 this.notifyObservers(content); // 調用通知方法-拉模型 // this.notifyObservers(); } }
2.編寫ConcreteObserver類
package com.myimooc.designpattern.c5observer.weatherjdk; import java.util.Observable; import java.util.Observer; /** * @describe 使用JDK實現觀察者模式,具體的觀察者對象 * @author zc * @version 1.0 2017-08-29 */ public class ConcreteObserver implements Observer { /** 觀察者的名稱,是誰收到了這個信息 */ private String observerName; @Override public void update(Observable o, Object arg) { // 推模型 System.out.println(observerName + " 收到了消息,目標推送過來的是 "+arg); // 拉模型 ConcreteWeatherSubject concreteWeatherSubject = (ConcreteWeatherSubject)o; System.out.println(observerName + " 收到了消息,主動到目標對象中去拉 "+concreteWeatherSubject.getContent()); } public String getObserverName() { return observerName; } public void setObserverName(String observerName) { this.observerName = observerName; } }
3.編寫Client類
package com.myimooc.designpattern.c5observer.weatherjdk; /** * @describe 使用JDK實現觀察者模式,測試類 * @author zc * @version 1.0 2017-08-29 */ public class Client { public static void main(String[] args) { // 創建天氣作為一個目標,也可以說是被觀察者 ConcreteWeatherSubject subject = new ConcreteWeatherSubject(); // 創建黃明的女朋友作為觀察者 ConcreteObserver observerGiel = new ConcreteObserver(); observerGiel.setObserverName("黃明的女朋友"); // 創建黃明的老媽作為觀察者 ConcreteObserver observerMum = new ConcreteObserver(); observerMum.setObserverName("老媽"); // 注冊觀察者 subject.addObserver(observerGiel); subject.addObserver(observerMum); // 目標更新天氣情況 subject.setContent("明天 天氣晴朗,藍天白云,氣溫28℃"); } }3-4 優點缺點
簡述觀察者優缺點
優點 觀察者模式實現了觀察者和目標之間的抽象耦合 觀察者模式實現了動態聯動(所謂聯動是指做一個操作會引起其它相關的操作) 觀察者模式支持廣播通信 缺點 可能會引起無謂的操作3-5 何時使用
觀察者模式的本質
觸發聯動
建議在以下情況中選用觀察者模式
當一個抽象模型有兩個方面,其中一個方面的操作依賴于另一個方面的狀態變化 如果在更改一個對象的時候,需要同時連帶改變其他的對象, 而且不知道究竟應該有多少對象需要被連帶改變 當一個對象必須通知其他的對象,但是又希望這個對象和被它通知的對象是松散耦合的第四章:觀察者模式衍生 4-1 特殊場景
需求總結
區別對待觀察者 需要根據不同的天氣情況來通知不同的觀察者 黃明的女朋友只想接收 下雨的天氣預報 黃明的老媽想接收 下雨或者下雪的天氣預報
解決思路
當天氣更新時,在目標天氣中進行判斷,如果不符合觀察者的條件,則不進行通知4-2 代碼示例
實現步驟
1.定義目標的抽象類和觀察者的接口 2.實現目標的類和觀察者接口 3.編寫測試類進行測試
代碼編寫
1.編寫WeatherSubject類
package com.myimooc.designpattern.c5observer.weathercondition; import java.util.ArrayList; import java.util.List; /** * @describe 天氣目標抽象類 * @author zc * @version 1.0 2017-08-29 */ public abstract class WeatherSubject { /** 用來保存注冊的觀察者對象 */ protected Listobservers = new ArrayList (); /** * 增加觀察者 */ public void attach(Observer observer){ observers.add(observer); } /** * 刪除觀察者 */ public void detach(Observer observer){ observers.remove(observer); } /** * 區別通知觀察者-由子類實現 */ protected abstract void notifyObservers(); }
2.編寫Observer類
package com.myimooc.designpattern.c5observer.weathercondition; /** * @describe 觀察者接口,定義一個更新的接口給那些在目標對象發生改變的時候被通知的對象 * @author zc * @version 1.0 2017-08-29 */ public interface Observer { /** * 更新的接口 * @param subject 傳入的目標對象,方便獲取相應的目標對象的狀態 */ void update(WeatherSubject subject); /** 設置觀察者名稱 */ void setObserverName(String observerName); /** 獲取觀察者名稱 */ String getObserverName(); }
3.編寫ConcreteWeatherSubject類
package com.myimooc.designpattern.c5observer.weathercondition; import java.util.Objects; /** * @describe 天氣目標的實現類 * @author zc * @version 1.0 2017-08-29 */ public class ConcreteWeatherSubject extends WeatherSubject { // 天氣情況:晴天、下雨、下雪 // 目標對象的狀態 private String weatherContent; @Override protected void notifyObservers() { // 遍歷所有注冊的觀察者 this.observers.forEach(observer -> { // 規則是: // 黃明的女朋友 需要 下雨 的條件通知,其他條件不通知 // 黃明的老媽 需要 下雨 或者 下雪 的條件通知,其他條件不通知 // 如果天氣是晴天 // do nothing... // 如果天氣是下雨 if(Objects.equals("下雨", this.getWeatherContent())){ if(Objects.equals("黃明的女朋友", observer.getObserverName())){ observer.update(this); } if(Objects.equals("黃明的老媽", observer.getObserverName())){ observer.update(this); } } // 如果天氣是下雪 if(Objects.equals("下雪", this.getWeatherContent())){ if(Objects.equals("黃明的老媽", observer.getObserverName())){ observer.update(this); } } }); } public String getWeatherContent() { return weatherContent; } public void setWeatherContent(String weatherContent) { this.weatherContent = weatherContent; this.notifyObservers(); } }
4.編寫ConcreteObserver類
package com.myimooc.designpattern.c5observer.weathercondition; /** * @describe 觀察者的實現類 * @author zc * @version 1.0 2017-08-29 */ public class ConcreteObserver implements Observer { /** * 觀察者的名稱,是誰收到了這個信息 */ private String observerName; /** * 天氣的內容信息,這個消息從目標處獲取 */ private String weatherContent; /** * 提醒的內容,不同的觀察者提醒不同的內容 */ private String remindThing; /** * 獲取目標類的狀態同步到觀察者的狀態中 */ @Override public void update(WeatherSubject subject) { weatherContent = ((ConcreteWeatherSubject)subject).getWeatherContent(); System.out.println(observerName + " 收到了天氣信息 " + weatherContent + ",準備去做 "+remindThing); } @Override public String getObserverName() { return observerName; } @Override public void setObserverName(String observerName) { this.observerName = observerName; } public String getWeatherContent() { return weatherContent; } public void setWeatherContent(String weatherContent) { this.weatherContent = weatherContent; } public String getRemindThing() { return remindThing; } public void setRemindThing(String remindThing) { this.remindThing = remindThing; } }
5.編寫Client類
package com.myimooc.designpattern.c5observer.weathercondition; /** * @describe 區別對待觀察者測試類 * @author zc * @version 1.0 2017-08-29 */ public class Client { public static void main(String[] args) { // 1.創建目標 ConcreteWeatherSubject weather = new ConcreteWeatherSubject(); // 2.創建觀察者 ConcreteObserver observerGiel = new ConcreteObserver(); observerGiel.setObserverName("黃明的女朋友"); observerGiel.setRemindThing("下雨了,安靜的呆在家里吧"); ConcreteObserver observerMum = new ConcreteObserver(); observerMum.setObserverName("黃明的老媽"); observerMum.setRemindThing("不管下雨還是下雪,我都不出門了"); // 3.注冊觀察者 weather.attach(observerGiel); weather.attach(observerMum); // 4.目標發布天氣 weather.setWeatherContent("天氣"); weather.setWeatherContent("下雪"); weather.setWeatherContent("下雨"); } }第五章:觀察者模式總結 5-1 課程總結
總結
觀察者模式簡介:場景描述 觀察者模式實戰:模式原理 觀察者模式詳解:推拉模型、JDK實現、優缺點 觀察者模式衍生:區別對待觀察者
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/70294.html
時間:2017年08月30日星期三說明:本文部分內容均來自慕課網。@慕課網:http://www.imooc.com教學源碼:https://github.com/zccodere/s...學習源碼:https://github.com/zccodere/s... 第一章:責任鏈模式簡介 1-1 課程簡介 課程大綱 什么是責任鏈模式 如何實現責任鏈模式 責任鏈模式如何解耦 責任鏈模式的應用 案例:...
時間:2017年08月27日星期日說明:本文部分內容均來自慕課網。@慕課網:http://www.imooc.com教學源碼:https://github.com/zccodere/s...學習源碼:https://github.com/zccodere/s... 第一章:單例模式簡介 1-1 簡介 單例模式 概念及應用場合 餓漢模式 懶漢模式 餓漢模式與懶漢模式的區別 什么是設計模式 是一套被反...
摘要:時間年月日星期二說明本文部分內容均來自慕課網。慕課網教學源碼學習源碼第一章適配器模式的簡介簡介生活中的適配器翻譯軟件插座適配器適配器模式定義適配器模式講將一個類的接口,轉換成客戶期望的另外一個接口。 時間:2017年08月29日星期二說明:本文部分內容均來自慕課網。@慕課網:http://www.imooc.com教學源碼:https://github.com/zccodere/s.....
摘要:時間年月日星期六說明本文部分內容均來自慕課網。案例介紹飲料機配置模版把水煮沸泡飲料把飲料倒進杯子加調味料第二章模版模式實現基本框架代碼編寫編寫類模版模式抽象基類,為所有子類提供一個算法框架。 時間:2017年09月02日星期六說明:本文部分內容均來自慕課網。@慕課網:http://www.imooc.com教學源碼:https://github.com/zccodere/s...學習源...
時間:2017年08月31日星期四說明:本文部分內容均來自慕課網。@慕課網:http://www.imooc.com教學源碼:https://github.com/zccodere/s...學習源碼:https://github.com/zccodere/s... 第一章:策略模式簡介 1-1 簡介 課程大綱 什么是策略模式 策略模式如何實現 策略模式總結篇 實例案例分享 日常生活中的策略 Wor...
閱讀 961·2023-04-26 02:49
閱讀 1171·2021-11-25 09:43
閱讀 2541·2021-11-18 10:02
閱讀 2919·2021-10-18 13:32
閱讀 1281·2019-08-30 13:54
閱讀 2073·2019-08-30 12:58
閱讀 3008·2019-08-29 14:06
閱讀 2154·2019-08-28 18:10