一、定義 允許一個對象在其內部狀態改變時改變它的行為,對象看起來似乎修改了它的類,狀態模式又稱為狀態對象,它是一種對象行為模式。 二、描述 狀態模式是一種較為複雜的設計模式,用於解決系統中複雜對象的狀態轉換以及不同狀態下行為的封裝問題,包含以下三個角色: 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)狀態模式對開閉原則的支持並不太好,增加新的狀態類需要修改負責狀態轉換的源代碼,否則無法轉換到新增狀態,而且修改某個狀態類的行為也需要修改對應類的源代碼。