State
: Alter an object's behavior when its state changes
每个人、事物在不同的状态下会有不同表现(动作),而一个状态又会在不同的表现下
转移到下一个不同的状态(
State
)。最简单的一个生活中的例子就是:地铁入口处,如果你
放入正确的地铁票,门就会打开让你通过。在出口处也是验票,如果正确你就可以
ok
,否
则就不让你通过(如果你动作野蛮,或许会有报警(
Alarm
),:))。
有限状态自动机(
FSM
)也是一个典型的状态不同,对输入有不同的响应(状态转移)。
通常我们在实现这类系统会使用到很多的
Switch/Case
语句,
Case
某种状态,发生什么动作,
Case
另外一种状态,则发生另外一种状态。但是这种实现方式至少有以下两个问题:
1
)当状态数目不是很多的时候,
Switch/Case
可能可以搞定。但是当状态数目很多的时
候(实际系统中也正是如此),维护一大组的
Switch/Case
语句将是一件异常困难并且容易出
错的事情。
2
)状态逻辑和动作实现没有分离。在很多的系统实现中,动作的实现代码直接写在状
态的逻辑当中。这带来的后果就是系统的扩展性和维护得不到保证。
模式选择
State
模式就是被用来解决上面列出的两个问题的,在
State
模式中我们将状态逻辑和动
作实现进行分离。当一个操作中要维护大量的
case
分支语句,并且这些分支依赖于对象的
状态。
State
模式将每一个分支都封装到独立的类中。
State
模式典型的结构图为:

This real-world code demonstrates the State pattern which allows an Account to behave differently depending on its balance. The difference in behavior is delegated to State objects called RedState, SilverState and GoldState. These states represent overdrawn accounts, starter accounts, and accounts in good standing.
// State pattern -- Real World example
|
using System; namespace DoFactory.GangOfFour.State.RealWorld { // MainApp test application class MainApp { static void Main() { // Open a new account Account account = new Account("Jim Johnson"); // Apply financial transactions account.Deposit(500.0); account.Deposit(300.0); account.Deposit(550.0); account.PayInterest(); account.Withdraw(2000.00); account.Withdraw(1100.00); // Wait for user Console.Read(); } } // "State" abstract class State { protected Account account; protected double balance; protected double interest; protected double lowerLimit; protected double upperLimit; // Properties public Account Account { get{ return account; } set{ account = value; } } public double Balance { get{ return balance; } set{ balance = value; } } public abstract void Deposit(double amount); public abstract void Withdraw(double amount); public abstract void PayInterest(); } // "ConcreteState" // Account is overdrawn class RedState : State { double serviceFee; // Constructor public RedState(State state) { this.balance = state.Balance; this.account = state.Account; Initialize(); } private void Initialize() { // Should come from a datasource interest = 0.0; lowerLimit = -100.0; upperLimit = 0.0; serviceFee = 15.00; } public override void Deposit(double amount) { balance += amount; StateChangeCheck(); } public override void Withdraw(double amount) { amount = amount - serviceFee; Console.WriteLine("No funds available for withdrawal!"); } public override void PayInterest() { // No interest is paid } private void StateChangeCheck() { if (balance > upperLimit) { account.State = new SilverState(this); } } } // "ConcreteState" // Silver is non-interest bearing state class SilverState : State { // Overloaded constructors public SilverState(State state) : this( state.Balance, state.Account) { } public SilverState(double balance, Account account) { this.balance = balance; this.account = account; Initialize(); } private void Initialize() { // Should come from a datasource interest = 0.0; lowerLimit = 0.0; upperLimit = 1000.0; } public override void Deposit(double amount) { balance += amount; StateChangeCheck(); } public override void Withdraw(double amount) { balance -= amount; StateChangeCheck(); } public override void PayInterest() { balance += interest * balance; StateChangeCheck(); } private void StateChangeCheck() { if (balance < lowerLimit) { account.State = new RedState(this); } else if (balance > upperLimit) { account.State = new GoldState(this); } } } // "ConcreteState" // Interest bearing state class GoldState : State { // Overloaded constructors public GoldState(State state) : this(state.Balance,state.Account) { } public GoldState(double balance, Account account) { this.balance = balance; this.account = account; Initialize(); } private void Initialize() { // Should come from a database interest = 0.05; lowerLimit = 1000.0; upperLimit = 10000000.0; } public override void Deposit(double amount) { balance += amount; StateChangeCheck(); } public override void Withdraw(double amount) { balance -= amount; StateChangeCheck(); } public override void PayInterest() { balance += interest * balance; StateChangeCheck(); } private void StateChangeCheck() { if (balance < 0.0) { account.State = new RedState(this); } else if (balance < lowerLimit) { account.State = new SilverState(this); } } } // "Context" class Account { private State state; private string owner; // Constructor public Account(string owner) { // New accounts are 'Silver' by default this.owner = owner; state = new SilverState(0.0, this); } // Properties public double Balance { get{ return state.Balance; } } public State State { get{ return state; } set{ state = value; } } public void Deposit(double amount) { state.Deposit(amount); Console.WriteLine("Deposited {0:C} --- ", amount); Console.WriteLine(" Balance = {0:C}", this.Balance); Console.WriteLine(" Status = {0}/n" , this.State.GetType().Name); Console.WriteLine(""); } public void Withdraw(double amount) { state.Withdraw(amount); Console.WriteLine("Withdrew {0:C} --- ", amount); Console.WriteLine(" Balance = {0:C}", this.Balance); Console.WriteLine(" Status = {0}/n" , this.State.GetType().Name); } public void PayInterest() { state.PayInterest(); Console.WriteLine("Interest Paid --- "); Console.WriteLine(" Balance = {0:C}", this.Balance); Console.WriteLine(" Status = {0}/n" , this.State.GetType().Name); } } } |
Output
Deposited $500.00 --- Balance = $500.00 Status = SilverState Deposited $300.00 --- Balance = $800.00 Status = SilverState Deposited $550.00 --- Balance = $1,350.00 Status = GoldState Interest Paid --- Balance = $1,417.50 Status = GoldState Withdrew $2,000.00 --- Balance = ($582.50) Status = RedState No funds available for withdrawal! Withdrew $1,100.00 --- Balance = ($582.50) Status = RedState |