設計模式(二十)狀態

来源:https://www.cnblogs.com/WinterSir/Undeclared/17523361.html
-Advertisement-
Play Games

一、定義 允許一個對象在其內部狀態改變時改變它的行為,對象看起來似乎修改了它的類,狀態模式又稱為狀態對象,它是一種對象行為模式。 二、描述 狀態模式是一種較為複雜的設計模式,用於解決系統中複雜對象的狀態轉換以及不同狀態下行為的封裝問題,包含以下三個角色: 1、Context(環境類):環境類又稱為上 ...


一、定義

允許一個對象在其內部狀態改變時改變它的行為,對象看起來似乎修改了它的類,狀態模式又稱為狀態對象,它是一種對象行為模式。

二、描述

狀態模式是一種較為複雜的設計模式,用於解決系統中複雜對象的狀態轉換以及不同狀態下行為的封裝問題,包含以下三個角色:
1、Context(環境類):環境類又稱為上下文類,它是擁有多種狀態的對象。由於環境類的狀態存在多樣性,且在不同狀態下對象的行為有所不同,所以將狀態獨立出去形成單獨的狀態類。在環境類中維護一個抽象狀態類State的實例,這個實例定義當前狀態,在具體實現時,它是一個State子類的對象。
2、State(抽象狀態類):它用於定義一個介面以封裝與環境類的一個特定狀態相關的行為,在抽象狀態類中聲明瞭各種不同狀態對應的方法,而在其子類中實現了這些方法,由於不同狀態下對象的行為可能不同,因此在不同子類中方法的實現可能存在不同,相同的方法可以寫在抽象狀態類中。
3、ConcreteState(具體狀態類):它是抽象狀態類的子類,每一個具體狀態類實現一個與環境類的一個狀態相關的行為,對應環境類的一個具體狀態,不同的具體狀態類其行為有所不同。

三、例子

X公司公司要為一銀行開發一套信用卡業務系統,銀行賬戶(Account)是該系統的核心類之一,通過分析,系統中賬戶存在3種狀態,根據餘額的不同,以上3種狀態可發生相互轉換,具體說明如下:
(1)如果賬戶中餘額大於等於0,則賬戶的狀態為正常狀態(Normal State),此時用戶既可以向該賬戶存款也可以從該賬戶取款。
(2)如果賬戶中餘額小於0,並且大於一2000,則賬戶的狀態為透支狀態(Overdraft State),此時用戶既可以向該賬戶存款也可以從該賬戶取款,但需要按天計算利息。
(3)如果賬戶中餘額等於-2000,那麼賬戶的狀態為受限狀態(Restricted State),此時用戶只能向該賬戶存款,不能再從中取款,同時也將按天計算利息。


Account:銀行賬戶,充當環境類

public class Account
{
    private AccountState state;  //維持一個對抽象狀態對象的引用
    private string owner;        //開戶名
    private double balance = 0;  //賬戶餘額
    public Account(string owner, double init)
    {
        this.owner = owner;
        this.balance = init;
        this.state = new NormalState(this);
        Console.WriteLine("{0}開戶,初始金額為{1}", this.owner, init);
        Console.WriteLine("------------------------------------");
    }
    //設置初始狀態
    public double Balance
    {
        get { return balance; }
        set { balance = value; }
    }
    public void SetState(AccountState state)
    {
        this.state = state;
    }
    public void Deposit(double amount)
    {
        Console.WriteLine("{0}存款{1}", this.owner, amount);
        state.Deposit(amount);// 調用狀態對象的Deposit()方法
        Console.WriteLine("現在餘額為{0}", this.Balance);
        Console.WriteLine("現在賬戶狀態為{0}", this.state.GetType().ToString());
        Console.WriteLine("------------------------------------");
    }
    public void Withdraw(double amount)
    {
        Console.WriteLine("{0}取款{1}", this.owner, amount);
        state.Withdraw(amount); //調用狀態對象的Withdraw()方法
        Console.WriteLine("現在餘額為{0}", this.Balance);
        Console.WriteLine("現在賬戶狀態為{0}", this.state.GetType().ToString());
        Console.WriteLine("------------------------------------");
    }
    public void ComputeInterest()
    {
        state.ComputeInterest();   //調用狀態對象的computeInterest方法
    }
}

AccountState:賬戶狀態類,充當抽象狀態類

public abstract class AccountState
{
    private Account acc;
    public Account Acc
    {
        get { return acc; }
        set { acc = value; }
    }
    public abstract void Deposit(double amount);
    public abstract void Withdraw(double amount);
    public abstract void ComputeInterest();
    public abstract void StateCheck();
}

NormalState、OverdraftState、RestrictedState:正常狀態、透支狀態、受限狀態,充當具體狀態類

public class NormalState : AccountState
{
    public NormalState(Account acc)
    {
        this.Acc = acc;
    }
    public NormalState(AccountState state)
    {
        this.Acc = state.Acc;
    }

    public override void Deposit(double amount)
    {
        Acc.Balance = Acc.Balance + amount;
        StateCheck();
    }
    public override void Withdraw(double amount)
    {
        Acc.Balance = Acc.Balance - amount;
        StateCheck();
    }

    public override void ComputeInterest()
    {
        Console.WriteLine("正常狀態,無需支付利息!");
    }

    public override void StateCheck()
    {
        if (Acc.Balance > -2000 && Acc.Balance <= 0)
        {
            Acc.SetState(new OverdraftState(this));
        }
        else if (Acc.Balance == -2000)
        {
            Acc.SetState(new RestrictedState(this));
        }
        else if (Acc.Balance < -2000)
        {
            Console.WriteLine("操作受限!");
        }
    }
}

public class OverdraftState : AccountState
{
    public OverdraftState(AccountState state)
    {
        this.Acc = state.Acc;
    }
    public override void Deposit(double amount)
    {
        Acc.Balance = Acc.Balance + amount;
        StateCheck();
    }
    public override void Withdraw(double amount)
    {
        Acc.Balance = Acc.Balance - amount;
        StateCheck();
    }

    public override void ComputeInterest()
    {
        Console.WriteLine("計算利息!");
    }

    public override void StateCheck()
    {
        if (Acc.Balance > 0)
        {
            Acc.SetState(new NormalState(this));
        }
        else if (Acc.Balance == -2000)
        {
            Acc.SetState(new OverdraftState(this));
        }
        else if (Acc.Balance < -2000)
        {
            Console.WriteLine("操作受限!");
        }
    }
}

public class RestrictedState : AccountState
{
    public RestrictedState(AccountState state)
    {
        this.Acc = state.Acc;
    }
    public override void Deposit(double amount)
    {
        Acc.Balance = Acc.Balance + amount;
        StateCheck();
    }
    public override void Withdraw(double amount)
    {
        Console.WriteLine("賬戶受限,取款失敗!");
    }

    public override void ComputeInterest()
    {
        Console.WriteLine("計算利息!");
    }

    public override void StateCheck()
    {
        if (Acc.Balance > 0)
        {
            Acc.SetState(new NormalState(this));
        }
        else if (Acc.Balance > -2000)
        {
            Acc.SetState(new OverdraftState(this));
        }
    }
}

Program:測試代碼

Account acc = new Account("段譽", 0.0);
acc.Deposit(1000);
acc.Withdraw(2000);
acc.Deposit(3000);
acc.Withdraw(4000);
acc.Withdraw(1000);
acc.ComputeInterest();
Console.ReadLine();

四、總結

1、優點

(1)狀態模式封裝了狀態的轉換規則,在狀態模式中可以將狀態的轉換代碼封裝在環境類或者具體狀態類中,可以對狀態轉換代碼進行集中管理,而不是分散在一個個業務方法中。
(2)狀態模式將所有與某個狀態有關的行為放到一個類中,只需註入一個不同的狀態對象即可使環境對象擁有不同的行為。
(3)狀態模式允許狀態轉換邏輯與狀態對象合成一體,而不是提供一個巨大的條件語句塊,狀態模式可以避免使用龐大的條件語句將業務方法和狀態轉換代碼交織在一起。
(4)狀態模式可以讓多個環境對象共用一個狀態對象,從而減少系統中對象的個數。

2、缺點

(1)狀態模式會增加系統中類和對象的個數,導致系統運行開銷增大。
(2)其結構與實現都較為複雜,如果使用不當將導致程式結構和代碼混亂,增加系統設計的難度。
(3)狀態模式對開閉原則的支持並不太好,增加新的狀態類需要修改負責狀態轉換的源代碼,否則無法轉換到新增狀態,而且修改某個狀態類的行為也需要修改對應類的源代碼。

測試簽名
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • GreatSQL社區全網開放且全免費的GCA和GCP雙等級考核認證,趕快來參與吧~ 認證課程介紹 GreatSQL社區開放GCA與GCP雙等級認證課程,課程全面覆蓋GreatSQL的安裝、使用、優化、安全高可用等方面,包含構建主從和MGR架構,優化提升性能,安全增強配置,SQL相容性改造,備份恢復和 ...
  • 大家好,我是獨孤風。元數據管理平臺層出不窮,但目前主流的還是Atlas、Datahub、Openmetadata三家,那麼我們該如何選擇呢? 本文就帶大家對比一下。要瞭解元數據管理平臺,先要從架構說起。 元數據管理的架構與開源方案 下麵介紹元數據管理的架構實現,不同的架構都對應了不同的開源實現。 下 ...
  • 原文地址: Android 藍牙使用 - Stars-One的雜貨小窩 公司項目需求需要實現監聽藍牙耳機連接,且要獲取藍牙耳機電量功能,翻了不少官方文檔,記錄下技術調研代碼 註:本文沒有研究藍牙配對功能 關於藍牙許可權適配 Android12以後,申請藍牙許可權需要申請一組,如新增的幾個許可權,需要一起申 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 概述 最近在負責公司官網的開發,在 H5 播放視頻時,遇到很多相容問題,所以總結下在 H5 播放時,遇到的相容性問題,並封裝一個 Video 的組件,便於在 H5 使用。 測試 先來測試一下在不同的瀏覽器,video 有什麼相容性的問題, ...
  • 項目中採用 wss 來建立的前後端連接, 但是並沒有用到認證的證書, 所以自己用 openssl 生成了私鑰, 自簽名證書來使用: 這裡就不再贅述 Wss 連接過程, 直接上手操作: 1. 生成私鑰, 證書: 請查看: 使用 openssl 安裝和生成證書 - 書源 - 博客園 (cnblogs.c ...
  • 一、為什麼要瞭解常見JS錯誤 1、調試和故障排除: 瞭解常見的JavaScript錯誤可以幫助你更好地調試和故障排除代碼。當你遇到錯誤時,能夠快速識別錯誤類型並找到解決方法,可以節省大量的時間和精力。 2、代碼質量和穩定性: 通過瞭解常見的JavaScript錯誤,你可以編寫更健壯和穩定的代碼。你可 ...
  • 項目代碼同步更新至碼雲 uni-vue3-ts-template 開發前準備 利用 uni-app 開發,有兩種方法: 通過 HBuilderX 創建(需安裝 HBuilderX 編輯器) 通過命令行創建(需安裝 NodeJS 環境),推薦使用 vscode 編輯器 這裡我們使用第2種方法,這兩種方 ...
  • 一、業務背景 系統業務功能:系統內部進行數據處理及整合, 對外部系統提供結果數據的初始化(寫)及查詢數據結果服務。 系統網路架構: 部署架構對切量上線的影響 - 內部管理系統上線對其他系統的讀業務無影響 分散式緩存可進行單獨擴容, 與存儲及查詢功能升級無關 通過緩存層的隔離, 系統擴展期間外部系統可 ...
一周排行
    -Advertisement-
    Play Games
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...