設計模式之狀態模式(二)

来源:https://www.cnblogs.com/dimple91/archive/2019/08/28/11423339.html
-Advertisement-
Play Games

在上一次的文章里,我們看到,需求的變更,迫使我們需要重新改造現有的糖果機代碼來符合這個新提的需求。但是,也並沒有難倒我們,至少我們在文末給出了思路和類圖,不知道你想的怎麼樣了呢。 我們不來虛的,直接進入正題,開啟我們的學習之旅。 實現我們的狀態類 現在是實現一個狀態的時候了:我們知道我們要的行為是什 ...


在上一次的文章里,我們看到,需求的變更,迫使我們需要重新改造現有的糖果機代碼來符合這個新提的需求。但是,也並沒有難倒我們,至少我們在文末給出了思路和類圖,不知道你想的怎麼樣了呢。

我們不來虛的,直接進入正題,開啟我們的學習之旅。

實現我們的狀態類

現在是實現一個狀態的時候了:我們知道我們要的行為是什麼,我們只需要把它變成代碼。我們打算完全遵守所寫下的狀態機代碼,但是這一次是分散在不同的類中。比如我們以NoQuarterState類為例。

public class NoQuarterState implements State {
    GumballMachine gumballMachine;
 
    public NoQuarterState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
 
    public void insertQuarter() {
        System.out.println("You inserted a quarter");
        gumballMachine.setState(gumballMachine.getHasQuarterState());
    }
 
    public void ejectQuarter() {
        System.out.println("You haven't inserted a quarter");
    }
 
    public void turnCrank() {
        System.out.println("You turned, but there's no quarter");
     }
 
    public void dispense() {
        System.out.println("You need to pay first");
    } 
    
}

在完成這些狀態類之前,我們需要重新改造糖果機,好讓你瞭解這一切的原理。我們把原來使用整數代表的狀態改為狀態對象:

    State soldOutState;
    State noQuarterState;
    State hasQuarterState;
    State soldState;
 
    State state;
    int count = 0;

這樣,我們就有了一個完整的糖果機類

public class GumballMachine {
 
    State soldOutState;
    State noQuarterState;
    State hasQuarterState;
    State soldState;
 
    State state;
    int count = 0;
 
    public GumballMachine(int numberGumballs) {
        soldOutState = new SoldOutState(this);
        noQuarterState = new NoQuarterState(this);
        hasQuarterState = new HasQuarterState(this);
        soldState = new SoldState(this);

        this.count = numberGumballs;
        if (numberGumballs > 0) {
            state = noQuarterState;
        } else {
            state = soldOutState;
        }
    }
 
    public void insertQuarter() {
        state.insertQuarter();
    }
 
    public void ejectQuarter() {
        state.ejectQuarter();
    }
 
    public void turnCrank() {
        state.turnCrank();
        state.dispense();
    }
 
    void releaseBall() {
        System.out.println("A gumball comes rolling out the slot...");
        if (count != 0) {
            count = count - 1;
        }
    }
 
    // 後面部分省略
}

好了,這樣子,我們就能繼續實現更多的狀態類了。比如我們能實現HasQuarterState和SoldState類

public class HasQuarterState implements State {
    GumballMachine gumballMachine;
 
    public HasQuarterState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
  
    public void insertQuarter() {
        System.out.println("You can't insert another quarter");
    }
 
    public void ejectQuarter() {
        System.out.println("Quarter returned");
        gumballMachine.setState(gumballMachine.getNoQuarterState());
    }
 
    public void turnCrank() {
        System.out.println("You turned...");
        gumballMachine.setState(gumballMachine.getSoldState());
    }

    public void dispense() {
        System.out.println("No gumball dispensed");
    }
    
}
public class SoldState implements State {
 
    GumballMachine gumballMachine;
 
    public SoldState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
       
    public void insertQuarter() {
        System.out.println("Please wait, we're already giving you a gumball");
    }
 
    public void ejectQuarter() {
        System.out.println("Sorry, you already turned the crank");
    }
 
    public void turnCrank() {
        System.out.println("Turning twice doesn't get you another gumball!");
    }
 
    public void dispense() {
        gumballMachine.releaseBall();
        if (gumballMachine.getCount() > 0) {
            gumballMachine.setState(gumballMachine.getNoQuarterState());
        } else {
            System.out.println("Oops, out of gumballs!");
            gumballMachine.setState(gumballMachine.getSoldOutState());
        }
    }
    
}

檢查一下,到目前為止我們做了啥

你現在有了一個糖果機的實現,他在結構上和前一個版本差異很大,但是功能上卻是一樣的。我們發現,你已經實現了以下幾點:

  • 將每個狀態的行為局部化到它自己的類中

  • 將容易產生問題的if語句刪除,以方便日後的維護

  • 讓每個狀態“對修改關閉”,讓糖果機“對擴展開放”,因為可以加入新的狀態類

  • 創建一個新的代碼基和類結構,這更能映射萬能糖果公司的圖,而且更容易閱讀和理解

定義狀態模式

是的,就在剛纔,我們已經實現了狀態模式。現在讓我們來看看什麼是狀態模式。

狀態模式允許對象在內部狀態改變時改變它的行為,對象看起來好像修改了它的類。

讓我們好好看下狀態模式的類圖:

這個類圖和策略模式的類圖是一樣的。但是雖然類圖是一樣的,但是兩個模式的差別在於它們的“意圖”不同。狀態模式將一群行為封裝在狀態對象中,context行為隨時可委托到那些狀態對象中的一個。對於策略模式而言,客戶通常主動指定context所要組合的策略對象是哪一個。

等等等等,之前不是說有十次抽中一次的游戲嗎?怎麼還沒寫出來呢?哈哈哈哈,不急不急,以上內容你都消化了嗎?如果你消化的話,請你耐心等待,倘若沒有,那請你先好好學習這些吧。我將在下次把抽獎這個搞定。

拜拜!

「奔跑吧攻城獅」感謝大家的關註,現在後臺回覆「設計模式」贈你小編精心挑選設計模式書籍。小編最近開竅,組建了一個技術交流群,回覆「加群」即可解鎖。


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

-Advertisement-
Play Games
更多相關文章
  • html中'disabled'與'readonly'的區別 此隨筆增量編輯 1. disabled 在提交表單的時候 值不會帶入表單中, 而readonly則可以將值帶入表單中. ...
  • ~~~ //立即執行函數 (function flexible(window, document) { // 獲取的html 的根元素 var docEl = document.documentElement; // dpr 物理像素比 var dpr = window.devicePixelRat ...
  • 摘要: 簡單實用的新特性。 原文: "ES新提案:雙問號操作符" 譯者:前端小智 本文主要講 Gabriel Isenberg 撰寫的ES提案[“Nullish coalescing for JavaScript”][2]。 它提出 替換 的運算符,並提供預設值。這裡先把這相提案叫作 雙問號操作符 ...
  • 前言:微信小程式中經常需要用到this.setData({})把變數值渲染到視圖層,那到底什麼是this.setData,如何使用?需要註意哪些?作為一個初學者,分享一點我的經驗,希望大家批評指正。 介紹:setData函數主要用於將邏輯層數據發送到視圖層,同時對應的改變this.data.x的值。 ...
  • 1.分號與換行 這個例子看上去沒有什麼不同,但是實質上,確實是不同的。第一個輸出結果為一個object ,而第二個輸出結果為undefined。為什麼? 因為Js中是不需要分號和換行這個東西的,第二個會被解析成: 所以實質上返回的是一個undefined。 2.五大類型中,關於null Js有五大數 ...
  • //獲取xpath function readXPath(element) { if (element.id !== "") {//判斷id屬性,如果這個元素有id,則顯 示//*[@id="xPath"] 形式內容 return '//*[@id=\"' + element.id + '\"]';... ...
  • 0828自我總結 Vue部分編譯不生效,解決Vue渲染時候會閃一下 一.Vue編譯不生效 在標簽里添加 二.解決Vue渲染時候會閃一下 方法一: 方法二: 利用 在載入vue完成後他會消失,專業術語叫斗篷 ...
  • 1. 二進位做許可權的優點 大家都知道,在Linux操作系統中,x - 可執行許可權,w - 可寫許可權 , r - 可讀許可權。其許可權值分別是1,2,4,但是有沒有想過為什麼是1,2,4 而不是 1,2,3 呢? OK , 現在是不是發現 1,2,4 分別對應著2的冪次方(2^0、2^1 、2^2),在計... ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...