大話設計模式筆記(十三)の狀態模式

来源:https://www.cnblogs.com/call-me-devil/archive/2019/08/03/11295085.html
-Advertisement-
Play Games

舉個慄子 問題描述 上班的日子,上午狀態好,中午想睡覺,下午漸恢復,加班苦煎熬。根據時間的不同體現不同的工作狀態。 簡單實現 Work / 抽象狀態 Created by callmeDevil on 2019/8/3. / public abstract class State { public ...


舉個慄子

問題描述

上班的日子,上午狀態好,中午想睡覺,下午漸恢復,加班苦煎熬。根據時間的不同體現不同的工作狀態。

簡單實現

Work

/**
 * 工作類
 * Created by callmeDevil on 2019/8/3.
 */
public class Work {

    private int hour;
    private boolean finish = false;

    public void writeProgram() {
        if (hour < 12) {
            System.out.println(String.format("當前時間:%s點,上午工作,精神百倍", hour));
        } else if (hour < 13) {
            System.out.println(String.format("當前時間:%s點,餓了,午飯;犯困,午休", hour));
        } else if (hour < 17) {
            System.out.println(String.format("當前時間:%s點,下午狀態還不錯,繼續努力", hour));
        } else {
            if (finish) {
                System.out.println(String.format("當前時間:%s點,下班回家了", hour));
            } else {
                if (hour < 21) {
                    System.out.println(String.format("當前時間:%s點,加班哦,疲累至極", hour));
                } else {
                    System.out.println(String.format("當前時間:%s點,不行了,睡著了", hour));
                }
            }
        }
    }

    // 省略 get set 方法

}

測試

public class Test {
    public static void main(String[] args) {
        // 緊急項目
        Work emergencyProjects = new Work();
        emergencyProjects.setHour(9);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(10);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(11);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(12);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(13);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(14);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(17);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(19);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(22);
        emergencyProjects.writeProgram();
        System.out.println("--------------------------");
        emergencyProjects.setFinish(true);
        emergencyProjects.setHour(19);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(22);
        emergencyProjects.writeProgram();
    }
}

測試結果

當前時間:9點,上午工作,精神百倍
當前時間:10點,上午工作,精神百倍
當前時間:11點,上午工作,精神百倍
當前時間:12點,餓了,午飯;犯困,午休
當前時間:13點,下午狀態還不錯,繼續努力
當前時間:14點,下午狀態還不錯,繼續努力
當前時間:17點,加班哦,疲累至極
當前時間:19點,加班哦,疲累至極
當前時間:22點,不行了,睡著了
--------------------------
當前時間:19點,下班回家了
當前時間:22點,下班回家了

存在問題

面向對象設計其實就是希望做到代碼的責任分解。 這個類違背了“單一職責原則”。如果公司為了員工的安全而要求員工必須20點之前離開公司(想想就好,現實往往不可能。。),那就會對當前的方法改動,維護出錯的風險很大,這點來說違背了“開放-封閉原則”。

狀態模式

定義

當一個對象的內在狀態改變時允許改變其行為,這個對象看起來像是改變了其類。

狀態模式主要解決的是當控制一個對象狀態轉換的條件表達式過於複雜時的情況。把狀態的判斷邏輯轉移到表示不同狀態的一系列類當中,可以把複雜的判斷邏輯簡化。當然,如果這個狀態判斷很簡單,那就沒必要用狀態模式了。

UML圖

代碼實現

State

/**
 * 抽象狀態
 * Created by callmeDevil on 2019/8/3.
 */
public abstract class State {
    public abstract void writeProgram(Work work);
}

ForenoonState

/**
 * 上午工作狀態
 * Created by callmeDevil on 2019/8/3.
 */
public class ForenoonState extends State{
    @Override
    public void writeProgram(Work work) {
        if (work.getHour() < 12) {
            System.out.println(String.format("當前時間:%s點,上午工作,精神百倍", work.getHour()));
        } else {
            // 超過12點,轉入中午工作狀態
            work.setState(new NoonState());
            work.writeProgram();
        }
    }
}

NoonState

/**
 * 中午工作狀態
 * Created by callmeDevil on 2019/8/3.
 */
public class NoonState extends State{
    @Override
    public void writeProgram(Work work) {
        if (work.getHour() < 13) {
            System.out.println(String.format("當前時間:%s點,餓了,午飯;犯困,午休", work.getHour()));
        } else {
            // 超過13點,轉入下午工作狀態
            work.setState(new AfternoonState());
            work.writeProgram();
        }
    }
}

AfternoonState

/**
 * 下午工作狀態
 * Created by callmeDevil on 2019/8/3.
 */
public class AfternoonState extends State{
    @Override
    public void writeProgram(Work work) {
        if (work.getHour() < 17) {
            System.out.println(String.format("當前時間:%s點,下午狀態還不錯,繼續努力", work.getHour()));
        } else {
            // 超過17點,轉入傍晚工作狀態
            work.setState(new EveningState());
            work.writeProgram();
        }
    }
}

EveningState

/**
 * 傍晚工作狀態
 * Created by callmeDevil on 2019/8/3.
 */
public class EveningState extends State {
    @Override
    public void writeProgram(Work work) {
        if (work.isTaskFinished()) {
            // 如果完成任務,轉入下班狀態
            work.setState(new RestState());
        } else {
            if (work.getHour() < 21) {
                System.out.println(String.format("當前時間:%s點,加班哦,疲累至極", work.getHour()));
            } else {
                // 超過21點,轉入睡眠工作狀態
                work.setState(new SleepingState());
                work.writeProgram();
            }
        }
    }
}

SleepingState

/**
 * 睡眠工作狀態
 * Created by callmeDevil on 2019/8/3.
 */
public class SleepingState extends State{
    @Override
    public void writeProgram(Work work) {
        System.out.println(String.format("當前時間:%s點,不行了,睡著了", work.getHour()));
    }
}

RestState

/**
 * 下班工作狀態
 * Created by callmeDevil on 2019/8/3.
 */
public class RestState extends State{
    @Override
    public void writeProgram(Work work) {
        System.out.println(String.format("當前時間:%s點,下班回家了", work.getHour()));
    }
}

Work

/**
 * 工作類,此時沒有了過長的分支判斷語句
 * Created by callmeDevil on 2019/8/3.
 */
public class Work {

    private State current;
    private int hour; // 時間,狀態轉換的依據
    private boolean taskFinished; // 任務完成,是否能下班的依據

    public Work(){
        // 工作初始化為上午工作狀態,即上午9點開始上班
        current = new ForenoonState();
    }

    public void writeProgram(){
        current.writeProgram(this);
    }

    // 省略 get set 方法

}

測試代碼與測試結果同上。

總結

  • 好處是將與特定狀態相關的行為局部化,並且將不同狀態的行為分割開來。
  • 將特定的狀態相關的行為都放入一個對象中,由於所有與狀態相關的代碼都存在於某個 ConcreteState 中,所以通過定義新的子類可以很容易的增加新的狀態和轉換。
  • 狀態模式通過把各種狀態轉移邏輯分佈到 State 的子類之間,來減少相互間的依賴。
  • 當一個對象的行為取決於它的狀態,並且必須在運行時根據狀態改變它的行為時,就可以考慮使用狀態模式。

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

-Advertisement-
Play Games
更多相關文章
  • 記錄一下我前段時間封裝的一個vue組件吧。技術需要積累,有時間我把我之前寫的還不錯的組件都開源出來。並嘗試vue和react 兩種方式的組件封裝。今天簡單寫下滑鼠框選div選中效果的封裝吧。 div框選實現 div框選效果,其實沒有什麼好的方法,就是獲取滑鼠事件,根據滑鼠的位置,動態創建一個跟隨滑鼠 ...
  • 說起網站調試,pc頁面和h5頁面,假如電腦上能夠重現的,都不在話下,調試起來都蠻簡單。僅僅需要fiddler一個抓包工具,把線上壓縮代碼替換成本地無壓縮代碼就可以了。具體步驟我後面可以詳細介紹。但是,僅僅是某款手機重現,其他手機沒有問題的情況下如何調試?hybrid頁面如何調試呢?這篇文章簡單總結下 ...
  • 特色:寫法更加優雅,更加像面像對象的編程,其思想和 ES5 是一致的。 箭頭函數、this ES6中可以使用 => 作為函數表達形式,極簡風格,參數+ => +函數體。 var foo = function(){return 1;}; //等價於 let foo = () => 1; let num ...
  • HTML屬性 屬性 描述 class 為html元素定義一個或多個類名(classname)(類名從樣式文件引入) id 定義元素的唯一id style 規定元素的行內樣式(inline style) title 描述了元素的額外信息 (作為工具條使用) HTML <head> 元素 <head> ...
  • 首先來瞄一下background-clip,這個屬性是幹嘛的? 顧名思義,背景裁剪... 按照我自己的理解就是背景的顯示區域 此處粘上MDN的示例鏈接(嫌麻煩的,後面我也貼上截圖)https://developer.mozilla.org/zh-CN/docs/Web/CSS/background- ...
  • 變數的作用域在函數之外聲明的變數,叫做全局變數,因為它可被當前文檔中的任何其他代碼所訪問。在函數內部聲明的變數,叫做局部變數,因為它只能在當前函數的內部訪問。 ECMAScript 6 之前的 JavaScript 沒有 語句塊作用域;相反,語句塊中聲明的變數將成為語句塊所在函數(或全局作用域)的局 ...
  • 在 jQuery 中可以使用 hide() 和 show() 方法來隱藏和顯示 HTML 元素 ...
  • 示例代碼托管在: "http://www.github.com/dashnowords/blogs" 博客園地址: "《大史住在大前端》原創博文目錄" 華為雲社區地址: "【你要的前端打怪升級指南】" [TOC] 一. 需求描述 前端工程出包後實現簡易的自動化部署。 二. 預備知識 網站的建設可以使 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...