《Head First設計模式》批注系列(一)——觀察者設計模式

  最近在讀《Head First設計模式》一書,此系列會引用源書內容,但文章內容會更加直接,以及加入一些自己的理解。

  觀察者模式(有時又被稱為模型-視圖(View)模式、源-收聽者(Listener)模式或從屬者模式)。在此種模式中,一個目標物件管理所有相依于它的觀察者物件,并且在它本身的狀態改變時主動發出通知。這通常透過呼叫各觀察者所提供的方法來實現。此種模式通常被用來實現事件處理系統。

  引子

  我們的公司剛剛你拿下了一個中國氣象局的一個招標,負責建立北京市的氣象觀測站。該氣象站必須建立在中國氣象局專利申請中的WeatherData對象上,有WeatherData對象負責追蹤目前的天氣狀況,(由于本文只做例子,只追蹤溫度、濕度、氣壓)。氣象站提出應用的要求:

  1、我們公司能建立一個應用,有三種布告板,可以顯示實時天氣狀況、氣象統計、以及簡單的預報。

  2、當WeatherData對象獲得最新的測量數據時,三種布告板必須實時更新。

  3、我們的氣象站是可以擴展的,氣象站希望可以公布一組API(接口),好讓其他開發人員可以自己寫出自己的氣象公告板,并插入此應用

  初步設計

  1、首先根據氣象站的需求,我們畫一個示意圖。

  

  WeatherData對象知道如何跟物理氣象站聯系,當數據跟新時,WeatherData對象從氣象站獲得數據,WeatherData對象隨機更新三個布告板的顯示:目前狀況(溫度、濕度、氣壓)、氣象統計和天氣預報,所以我們目前的主要任務是,利用WeatherData對象從氣象站獲取數據,并跟新三個布告板。

  在設計之前,我們要看一看氣象站給我們WeatherData類(此處只做示意,代碼后面會變得完整)

public class WeatherData {//下面的三個方法獲取溫度、濕度、以及壓力public float getTemperature(){temperature=獲取溫度;return temperature;}public float getHumidity(){temperature=獲取濕度;return humidity;}public float getPressure(){temperature=獲取壓力;return pressure;}//一旦氣象測量更新、此方法就會被調用public void measurementsChanged(){}

  好了,到此為止我們已經知道了最終的設計要求以及氣象站給我們的WeatherData類,下面我們就要開始設計我們的應用,根據我們知道的東西,我們可以先來一個不完整的初版,我們現在WeatherData中增加一些方法(不著急先寫出方法的具體內容,只要寫出一個方法名,記得它的功能即可)

public?class?WeatherData {    
//下面的三個方法獲取溫度、濕度、以及壓力public float getTemperature(){temperature=獲取溫度;return temperature;}public float getHumidity(){temperature=獲取濕度;return humidity;}public float getPressure(){temperature=獲取壓力;return pressure;}//一旦氣象測量更新、此方法就會被調用public void measurementsChanged(){float temp = getTemperature();float humidity = getHumidity();float pressure = getPressure();

     currentConditionsDisplay.update(temp,humidity,pressure);
     statisticsDiaplay.updata(temp,humidity,pressure);
     forecastDisplay.update(temp,humidity,pressure);}

  這是我們第一次設計的程序,由于我們已經開始準備用設計模式了,所以我們可以看看我們目前的代碼中是不是有還可以改進的地方,首先,我們看到了三個公告板都有update方法,那我們就可以把這個方法

抽取成一個接口,這樣我們每次增加公告板時直接實現此接口就可以,其次,本次我們討論的是觀察者模式,那我們的引子就先說到這,我們開始看看什么是觀察者設計模式,我們了解完觀察者設計模式后,我們

再回到我們的引子,完成設計。

  認識觀察者設計模式

  在生活中,訂閱報紙就是就是一個觀察者設計模式,報社的業務就是出版報紙,當你訂閱了某家報社的報紙,只要報社有了新的報紙出版,他們就會給你送來,只要你是他們的訂戶,你就一定會收到報

紙,當你不想在看這家報紙時,你就可以取消訂閱,他們就不會再送來新報紙。其實,出版社+訂閱者就等于觀察者模式,只是在這個模式里,出版社叫做“主題(Subject)”,訂閱者叫做觀察者"(Observer)”,如果

你還沒有看懂,那我們來看下面這個圖:

  

  圖中主題對象管理者int數據,狗對象、貓對象、老鼠對象訂閱了主題,一旦主題對象發生改變,就會給這些訂閱了的對象發送數據,鴨子對象沒有訂閱主題,就不會接收到數據。

  有一天,鴨子對象突然對主題對象管理的數據起了興趣,它就需要過去告訴主題,我對你的數據改變有興趣,一有變化請告訴我,這就是“訂閱”的過程,在這之后,鴨子對象就是正式

的觀察者了,以后主題管理的數據再有改變就會告訴鴨子對象。

  又有一天,老鼠對象對主題說,你管理的數據我觀察太久了,我不想再當你的觀察者了,這時主題就刪掉老鼠對象,每當數據再變化時,老鼠對象就不會接收到數據。

  觀察者設計模式定義了對象之間的一對多依賴,這樣的依賴,當一個對象改變時,它的所有依賴者都會受到通知并自動更新

  下面是便是定義觀察者設計模式的類圖:

  

  觀察者設計模式應用到我們的氣象站中

  我們已經基本了解了觀察者設計模式,那我們就可以回到我們的引子完成原來的設計

  初步思考

  通過我們在上面分析的觀察者設計模式,我們發現這是模式是一對多的關系,每當一改變時,就會給多發送改變的數據,而在我們的氣象站設計中,正是一對多的關系,一就是我們的WeatherData數據

多就是顯示的布告板,而不同的布告板有相同和不同的方法,我們可以把相同的部分抽取成接口,實現代碼的復用,那么下面就讓我們參照上面觀察者設計模式的類圖畫一下我們氣象站的設計類圖。(自己

先嘗試一下喲)

  設計氣象站

  

    實現氣象站

    根據上面的類圖,我們就可以完善我們的代碼啦

    Subject類的接口及WeatherData實現

package com.frank.observe.subject;
import com.frank.observe.observer.Observer;public interface Subject {
  //主題注冊、刪除、通知觀察者方法
public void registerObserver(Observer o);public void removeObserver(Observer o);public void notifyObserver();//信息改變時執行方法public void measurementsChanged(); }

?

package com.frank.observe.subject;
import java.util.ArrayList;
import com.frank.observe.observer.Observer;public class WeatherData implements Subject {
  //WeatherData實現了Subject方法
private ArrayList<Observer> observers;
  //包含溫度、濕度、壓力
private float temperature;private float humidity;private float pressure;//構造器創建觀察者們的集合public WeatherData(){observers = new ArrayList<Observer>();}//接口方法@Overridepublic void registerObserver(Observer o) {observers.add(o);}@Overridepublic void removeObserver(Observer o) {int i = observers.indexOf(o);if(i>=0){observers.remove(o);}}@Overridepublic void notifyObserver() {for(int i = 0;i<observers.size();i++){Observer observer = observers.get(i);observer.update(temperature, humidity, pressure);}}@Overridepublic void measurementsChanged() {notifyObserver();}//WeatherData自己的set方法,一會測試時在test中改變數據源public void setMeasurements(float temperature,float humidity, float pressure){this.temperature=temperature;this.humidity=humidity;this.pressure=pressure;measurementsChanged();}}

?

?   Observer類的接口以及CurrentConditionDisplay實現

package com.frank.observe.observer;
//Observer接口中更新數據的方法
public interface Observer {public void update(float temp,float humidity,float pressure);
}
package com.frank.observe.observer;
import com.frank.observe.display.DisplayElement;
import com.frank.observe.subject.Subject;
import com.frank.observe.subject.WeatherData;
//顯示板要實現Observer以及DisplayElement接口(及公共方法)
public class CurrentConditionDisplay implements Observer, DisplayElement {private float temprature;private float humidity;
  //將weatherData作為自己的成員變量
private Subject weatherData;//在帶參構造器中將自己注冊到weatherData中public CurrentConditionDisplay(Subject weatherData){this.weatherData=weatherData;weatherData.registerObserver(this);}//接口的更新方法@Overridepublic void update(float temp, float humidity, float pressure) {this.temprature=temp;this.humidity=humidity;
     //接口的顯示方法display();}@Override
public void display() {System.out.println("current conditions" +temprature+"F degrees and"+humidity+"% humidity");}}

?

  DisplayElement接口

package com.frank.observe.display;public interface DisplayElement {public void display();
}

  Test方法

package com.frank.observe.test;
import com.frank.observe.observer.CurrentConditionDisplay;
import com.frank.observe.subject.WeatherData;public class Test {public static void main(String[] args) {
     //新建一個主題WeatherData weatherData
= new WeatherData();
     //新建一個公告板并將自己注冊到主題中CurrentConditionDisplay currentDisplay
= new CurrentConditionDisplay(weatherData);
     //每當主題更新數據時發送給觀察者,觀察者顯示在公告板中weatherData.setMeasurements(
80, 60, 30.4f);weatherData.setMeasurements(82, 70, 29.2f);weatherData.setMeasurements(78, 90, 29.2f);}}

?

?  結果

current conditions80.0F degrees and60.0% humidity
current conditions82.0F degrees and70.0% humidity
current conditions78.0F degrees and90.0% humidity

?

?  總結

   要點:

OO基礎:抽象

OO原則:封裝變化、多用組合,少用繼承、針對接口編程,不針對實現編程

OO模式:觀察者設計模式----在對象之間定義一對多的依賴,這樣一來,當一個對象改變狀態,依賴它的對象都會受到通知,并自動更新(后面的系列會看到其代表人物--MVC)

?  

?

轉載于:https://www.cnblogs.com/FrancisLiu/p/8728070.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/251987.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/251987.shtml
英文地址,請注明出處:http://en.pswp.cn/news/251987.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

PYPL 4 月排行:Python 最流行,Java 還行不行?

開發四年只會寫業務代碼&#xff0c;分布式高并發都不會還做程序員&#xff1f; PYPL 發布了 4 月份的編程語言排行榜。 前五的分別是&#xff1a;Python、Java、Javascript、C# 和 PHP。可以看到&#xff0c;榜單沒有什么大變化&#xff0c;但是相比去年 4 月份&#xff0c;…

兩個向量的旋轉矩陣與四元素

兩向量的夾角 2017年06月20日 17:38:11 csxiaoshui 閱讀數&#xff1a;36764 怎么計算兩個向量間的夾角呢&#xff1f; 這里主要分兩種情況&#xff0c;對于二維向量和三維向量來分別討論。 1. 二維向量 二維向量的情況相對簡單&#xff0c;根據向量間的點乘關系 v1?v2|…

順序表

一、數據是如何在內存中存儲的&#xff1f; 32位系統中char&#xff0c;int型數據在內存中的存儲方式&#xff1a; char占1byte&#xff08;8bit&#xff09;int占4byte&#xff08;32bit&#xff09;假設我們有一個int類型的值&#xff0c;它從0x01開始&#xff0c;一個int占據…

Establishing SSL connection without server's identity verification is not recommended.

完全描述:Establishing SSL connection without servers identity verification is not recommended. According to MySQL 5.5.45, 5.6.26 and 5.7.6 requirements SSL connection must be established by default if explicit option isnt set. For compliance with existing …

四元素的真面目..........簡單粗暴

作者&#xff1a;Yang Eninala 鏈接&#xff1a;https://www.zhihu.com/question/23005815/answer/33971127 來源&#xff1a;知乎 著作權歸作者所有。商業轉載請聯系作者獲得授權&#xff0c;非商業轉載請注明出處。 根據我的理解&#xff0c;大多數人用漢密爾頓四元數就只…

2.自定義變量調節器

① 使用registerPlugin()方法來擴充變量調節器 該方法接收3個參數 1. 字符串modifier 2. 插件函數的名字 3. PHP回調函數 示例&#xff1a;自定義一個變量調節器&#xff0c;可以改變文字的顏色和大小 第一步&#xff1a;調用smarty對象的registerPlugin&#xff08;&#x…

SpringBoot2構建基于RBAC權限模型的駕校代理小程序后端

本項目是使用SpringBoot2構建的一套基于RBAC權限模型的后臺管理系統&#xff0c;前端是微信小程序。 項目地址: github.com/fuyunwang/D… 項目的緣由 最近接了個外包,主要是針對于駕校開發一個代理小程序。目的是為了方便駕校的管理來招攬學員,同時方便維護學員和代理信息。 項…

while read line的問題

循環中的重定向或許你應該在其他腳本中見過下面的這種寫法&#xff1a;while read linedo…done < file剛開始看到這種結構時&#xff0c;很難理解< file是如何與循環配合在一起工作的。因為循環內有很多條命令&#xff0c;而我們之前接觸的重定向都是為一條命令工作的。…

Linemod;理解

Linemod 代碼筆記 2019年03月11日 16:18:30 haithink 閱讀數&#xff1a;197 最近了解到 Linemod 這個模板匹配算法&#xff0c;印象不錯 準備仔細學習一下&#xff0c;先做點代碼筆記&#xff0c;免得后面不好回顧 目前的筆記基本上把 核心流程都分析得比較清楚了&#xff0…

Swift3中數組創建方法

轉載自&#xff1a;http://blog.csdn.net/bwf_erg/article/details/70858865 數組是由一組類型相同的元素構成的有序數據集合。數組中的集合元素是有 序的&#xff0c;而且可以重復出現。 1 數組創建 在Swift語言中&#xff0c;數組的類型格式為&#xff1a; Array<ElementT…

BZOJ 5249: [2018多省省隊聯測]IIIDX(貪心 + 線段樹)

題意 這一天&#xff0c;\(\mathrm{Konano}\) 接到了一個任務&#xff0c;他需要給正在制作中的游戲 \(\mathrm{《IIIDX》}\) 安排曲目 的解鎖順序。游戲內共有\(n\) 首曲目&#xff0c;每首曲目都會有一個難度 \(d\) &#xff0c;游戲內第 \(i\) 首曲目會在玩家 Pass 第 \(\lf…

手眼標定

Eye-in-hand和Eye-to-hand問題求解和實驗 2018年12月07日 00:00:40 百川木易 閱讀數 3018 2018/12/5 By Yang Yang&#xff08;yangyangipp.ac.cn&#xff09; 本文所有源碼和仿真場景文件全部公開&#xff0c;點擊Gitee倉庫鏈接。 文章目錄 問題描述Eye-in-hand問題求解公式…

RNN總結

RNN既可以表述為循環神 經網絡&#xff08;recurrent neural network&#xff09;&#xff0c;也可以表述為遞歸神經網絡&#xff08;recursive neural network&#xff09;&#xff0c;前者一般用于處理以時間序列為輸入的問題&#xff08;比如把一個句子看成詞組成的序列&…

Problem 2. number題解

number&#xff1a;數學二分圖匹配 首先&#xff0c;如果S<N,那么S1&#xff0c;S2...N這些數直接放在S1,S2...N的位置上(如果其他數x放在這些位置上面&#xff0c;這些數不放在對應位置&#xff0c;那么x一定能放在這些數放的位置&#xff0c;所以直接交換即可)所以可以直接…

SSD列子

一、介紹 本博文主要介紹實現通過SSD物體檢測方式實現工件裂紋檢測。裂紋圖像如下所示&#xff1a; 二、關于SSD算法 具體算法不再闡述&#xff0c;詳細請參考&#xff1a; https://blog.csdn.net/u013989576/article/details/73439202 https://blog.csdn.net/xiaohu2022/arti…

linux硬鏈接與軟鏈接

Linux 系統中有軟鏈接和硬鏈接兩種特殊的“文件”。 軟鏈接可以看作是Windows中的快捷方式&#xff0c;可以讓你快速鏈接到目標檔案或目錄。 硬鏈接則透過文件系統的inode來產生新檔名&#xff0c;而不是產生新檔案。 創建方法都很簡單&#xff1a; 軟鏈接&#xff08;符號鏈接…

int轉時間

int轉時間 public static string FormatDuration(int duration) { if (duration 0) return "00:00:00"; int hours duration / 3600; int minutes duration % 3600 / 60; int seconds duration % 3600 % 60; string _hours hours.ToString("00") &qu…

企業級區塊鏈現狀研究報告:小企業的投資總額是大企業的28倍

根據企業級區塊鏈現狀研究報告表明&#xff0c;當前企業采用區塊鏈技術的勢頭正在逐步增強。參與該報告的企業表示&#xff0c;區塊鏈投資今年共增長了 62% &#xff0c;預計到 2025 年區塊鏈將成為主流技術。其中&#xff0c;有 28% 的企業正在積極開展區塊鏈發展計劃。現在看…

特征匹配

Python 使用Opencv實現圖像特征檢測與匹配 2018-06-13 11:36:58 Xy-Huang 閱讀數 19203更多 分類專欄&#xff1a; Python 人工智能 版權聲明&#xff1a;本文為博主原創文章&#xff0c;遵循 CC 4.0 BY-SA 版權協議&#xff0c;轉載請附上原文出處鏈接和本聲明。 本文鏈接…

bzoj 1015 并查集

代碼&#xff1a; //這題可以反著想&#xff0c;把要去掉的點倒著處理變成往圖中一個一個的加點&#xff0c;然后用并查集處理聯通快就好了。 #include<iostream> #include<cstdio> #include<cstring> #include<vector> using namespace std; const in…