一起去開心的購物吧——淺談觀察者模式

来源:https://www.cnblogs.com/MrJR/archive/2019/02/28/10447978.html
-Advertisement-
Play Games

觀察者模式 嗨,大家好,我們又見面了,不知道上次的籃球比賽大家是不是還意猶未盡呢,沒看到的同學可以前往https://www.cnblogs.com/MrJR/p/10441166.html觀摩哦。 今天呢,我們來看另一個Java設計模式——觀察者模式。 顧名思義,觀察者模式,那肯定要有觀察者,既然 ...


觀察者模式

聲明:本文為原創,如有轉載請註明轉載與原作者並提供原文鏈接,僅為學習交流,本人才識短淺,如有錯誤,敬請指正

嗨,大家好,我們又見面了,不知道上次的籃球比賽大家是不是還意猶未盡呢,沒看到的同學可以前往https://www.cnblogs.com/MrJR/p/10441166.html觀摩哦。

今天呢,我們來看另一個Java設計模式——觀察者模式。

顧名思義,觀察者模式,那肯定要有觀察者,既然有了觀察者,肯定就有被觀察者,當然如果你說你就是喜歡發呆,啥都不觀察,當我沒說。

不能免俗,我們首先來看一下觀察者模式的官方定義:

觀察者模式:定義了對象之間的一對多依賴,當一個對象改變狀態時,他的所有依賴者都會收到通知並自動更新。

或許大家覺得這段話還蠻好理解的,畢竟沒啥專業術語,當一個對象改變了,他的依賴者都會收到通知:喂,我被改變了,你們也要快快行動起來啦,問題的關鍵在於,如何保證通知的靈活性。

不是所有的觀察者都想一直目不轉睛盯著同一個東西,拜托,那會把人逼瘋的,也會有人想一起加入觀察的行列,有什麼好東西呀,讓我康康,如果我們把觀察者與被觀察者聯繫的過於緊密,意味著每次做出改變都是一個浩大的工程,我們要反覆修改代碼,實現對不同的觀察者的通知,還記得我們的原則嗎,對擴展開放,對修改關閉。

好啦,我們先把這些苦惱丟到一邊,來看一下我們的新朋友,小王同學與小楊同學,她們可是一個十足的購物狂,每次逛街都能買好多的東西,最近呢,他們卻在為購物而煩惱,這是為什麼呢?我們來聽聽她們怎麼說的。

 

楊:雙十一馬上就要到了,我在購物網站看中了一款BB霜和一款新手機。

王:真巧,我也看中了這兩樣東西,咱們一起買沒準可以打折喲!

楊:買什麼呀買,根本就搶不到,每次等我反應過來的時候,早就賣光了!!

王:這倒是個問題,我也經常搶不到自己想要的東西。

楊:要是商品剛上架,我們就能接受到通知就好了。

王:這樣我們肯定就能搶到了。

 

作為一名程式員,我們是否應該立刻給兩位可愛的女士伸出援手呢,當然是啦,而在這裡,觀察者模式就可以大顯身手了。

我們可以看出,此處的觀察者就是小楊與小王,而主題呢,我這裡使用了主題二字,其實就是被觀察者,這是觀察者模式中的慣用說法,主題就是購物網站,而通知就是新商品的上架,最後觀察者的改變便是小楊與小王的買買買。

我們首先定義一個觀察者介面,這個介面定義了觀察者在收到通知後應該執行的方法

public interface Person {

    void buy(String productionName);
}

 

此處當然就是買買買的方法啦,我們會傳入一個商品名。

接下來我們定義主題介面

public interface ShoppingApp {

    void registerPerson(Person person);

    void removePerson(Person person);

    void notifyPerson();

}

主題介面就是購物APP,它有三個方法,相信通過方法名大家也能看出來它們的作用,分別是註冊觀察者,移除觀察者與通知觀察者。

然後,我們實現一個具體的購物網站。

public class TaoBao implements ShoppingApp {

    private LinkedList<Person> persons;
    private String productionName;

    public TaoBao(){
        persons = new LinkedList<>();
    }

    @Override
    public void registerPerson(Person person) {
        persons.add(person);
    }

    @Override
    public void removePerson(Person person) {
        if (persons.contains(person)){
            persons.remove(person);
        }else{
            System.out.println("錯誤操作,無法刪除不存在的用戶");
        }
    }

    @Override
    public void notifyPerson() {
        for(Person person : persons){
            person.buy(productionName);
        }
    }

    public void setProductionName(String productionName){
        this.productionName = productionName;
        notifyPerson();
    }
}

我們可以看到,在這個超迷你淘寶中,我們維護了一個鏈表,而這個鏈表儲存的就是所有正在觀察這個主題的觀察者們,當然,我們初始化時把他置空。

我們實現註冊觀察者,直接將觀察者對象添加進我們的觀察者列表即可。

我們實現移除觀察者,將觀察者從鏈表中移除即可。

我們重點看一下通知方法的實現以及通知方法如何被調用,我們可以看到,為了通知每個觀察者,我們遍歷了所有的觀察者們,然後調用了他們應對通知的方法,以表示他們已經接收到通知並做出了積極的回應,註意,我們一直使用的都是介面而不是具體類,我們只需要調用buy方法即可,根本不用去管到底是什麼觀察者,不管你是張三李四王五還是蜘蛛俠超人,反正我知道你肯定有buy這個方法,因為你實現了Person介面,這種針對介面編程而不是針對實現編程使我們的代碼完全與具體類解耦,我們不需要去管到底是什麼類在與我交互,畢竟如果你連這個介面都沒實現,編譯器都不會放過你的(笑)。

而在這個類里,我們何時通知觀察者取決於我們的商品是否上架,即productionName是否被設置了值,當淘寶商品上架,我們就會調用通知方法,通知所有的觀察者。

接下來,我們讓小王同學和小楊同學現身。

public class MissW implements Person {

    @Override
    public void buy(String productionName) {
        System.out.println("王小玲同學:"+productionName + "終於開售了,還好提前關註了!");
    }
}
public class MissY implements Person {

    @Override
    public void buy(String productionName) {
        System.out.println("楊小青同學:我要的" + productionName + "終於有貨了,我要趕緊搶!!");
    }
}

可以看出來,具體的觀察者實現觀察者介面後,只要按照自己的需求實現介面方法即可,在這裡,我們只是簡單的列印出一句話。

最後呢,當然就是我們的雙十一登場啦,小楊同學與小王同學早就按捺不住激動的心情,要搶購了,雙十一將檢測我們的代碼到底有沒有起到作用。

public class Double11 {

    public static void main(String[] args) {

        TaoBao taoBao = new TaoBao();

        MissW wang = new MissW();
        MissY yang = new MissY();

        taoBao.registerPerson(wang);
        taoBao.registerPerson(yang);

        taoBao.setProductionName("雅詩蘭黛高級BB霜");
        taoBao.setProductionName("華為Mate20 pro");
        
        taoBao.removePerson(wang);
        taoBao.setProductionName("悅詩風吟高級化妝禮盒");
    }
}

我們首先創建了超迷你淘寶對象作為具體主題,然後創建了小王同學與小楊同學作為具體觀察者,接著小王與小楊就註冊了淘寶,等著心儀的物品擺上貨架,接收通知。

12點的鐘聲剛過,他們心儀的東西終於擺上了貨架,我們來看運行結果,她們到底有沒有接收到通知呢?

看來我們的小楊同學與小王同學都成功收到了淘寶發出的通知,在搶購了自己喜歡的東西之後,小王同學退出了淘寶,不再接收淘寶發出的通知,更不會再去買東西,而小楊同學仍然能接收到淘寶發出的通知而繼續購物。

觀察者模式可以在不影響原主題通知與觀察者更新方法的基礎上,新增或移除觀察者,對擴展的開放,對修改的關閉的設計原則再一次展現了它強大的力量,同時我們還發現針對介面編程可以讓我們六根清凈,不必再被具體類所糾纏,這也是解耦的力量體現。

我們還要註意一件事,在購物的例子中,超迷你淘寶在商品上架後,主動給所有的觀察者“推送”了消息,觀察者則被動的接收消息,不管這個消息它是否需要(在我們的例子中,預設觀察者收到的消息都是她們需要的),有可能觀察者雖然關註了主題,但是只要主題的某些消息,那麼這裡就涉及到了另一種接收消息的方式——觀察者主動”拉“消息,通過主題的getter方法,觀察者可以主動去主題拉取自己需要的消息,根本應用場景的不同,兩種方式各有千秋,大家可以自己動手實現一下試試。

好的,伴隨著兩位美麗的女士錢包空空,我的淺談觀察者模式也就先到這裡了,我們下次再見哦。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 定義:定義一個創建產品對象的工廠介面,將實際創建工作推遲到子類當中。核心工廠類不再負責產品的創建,這樣核心類成為一個抽象工廠角色,僅負責具體工廠子類必須實現的介面,這樣進一步抽象化的好處是使得工廠方法模式可以使系統在不修改具體工廠角色的情況下引進新的產品。 工廠方法模式在簡單工廠模式的基礎上抽象出了 ...
  • 前言 開心一刻 說實話,作為一個宅男,每次被淘寶上的雄性店主追著喊親,親,親,這感覺真是噁心透頂,好像被強吻一樣。。。。。。。。。更煩的是我每次為了省錢,還得用個女號,跟那些店主說:“哥哥包郵嘛麽嘰。”,“哥哥再便宜點唄,我錢不夠了嘛,5555555,”。 知道後的店主 路漫漫其修遠兮,吾將上下而求 ...
  • 1. Python爬蟲入門教程 爬取背景 2019年1月10日深夜,打開了百思不得姐APP,想了一下是否可以爬呢?不自覺的安裝到了夜神模擬器裡面。這個APP還是比較有名和有意思的。 下麵是百思不得姐的簡介 年度超好玩的搞笑內容平臺,整個互聯網能嗨翻宇宙的神級腦洞大神段子手們都在這.. 新鮮的視頻,爆 ...
  • 題意 "題目鏈接" Sol 好像搞出了一個和題解不一樣的做法(然而我考場上沒寫出來還是爆零0) 一個很顯然的思路是考慮每個最小值的貢獻。 預處理出每個數左邊第一個比他小的數,右邊第一個比他大的數。 那麼$[L_i + 1, i]$對$[i, R_i]$中的每個數都會有$a[i]$的貢獻。 我們可以抽 ...
  • pip如今已經成為了Python的一大特色,可以很方便得協助Python開發者進行包管理。本文詳細介紹了pip命令的使用方法。 ...
  • __getattribute__ 官方文檔中描述如下: 該方法可以攔截對對象屬性的所有訪問企圖,當屬性被訪問時,自動調用該方法(只適用於新式類)。因此常用於實現一些訪問某屬性時執行一段代碼的特性。 需要註意的是,正式由於它攔截對所有屬性的訪問(包括對__dict__的訪問),在使用中要十分小心地避開 ...
  • IT是全國平均薪資最高的行業,2017年全國最高,人均13點4萬每年. 但技術固然好,創業拼的還是世界觀下的創意. 蘑菇街,並夕夕,TikTok,頭條,哪個不是創意用IT技術的現實化?? 未來,大平臺是Dio絲(歐拉木大)用的,中等偏上的人還是會用個人定製...上等人我不知道 加油吧,未來引擎是服務 ...
  • 發個致富腦洞:我就在想本人雖然單身,但本人戀愛經歷很多,追女生技術十足,女朋友漂亮又賢惠.如果本人開個平臺幫人誠心介紹女朋友,男女成男女朋友經男方同意我收2.5萬(IT界平均月收入的1.5倍不到),雙方結婚我再收2.5萬,總共5萬.如果沒結婚隨時可退錢,房產證做抵押,不知道行不行啊...本著給極少數 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...