Terry's blog

Focus on bigdata and cloud.

博客园 首页 新随笔 联系 订阅 管理
对象状态影响对象行为:
    对象拥有不同的状态,往往会行使不同的行为...
                  
动机:
    在软件构建过程中,某些对象的状态如果改变以及其行为也会随之而发生变化,比如文档处于只读状态,其支持的行为和读写状态支持的行为就可能完全不同。
    如何在运行时根据对象的状态来透明更改对象的行为?而不会为对象操作和状态转化之间引入紧耦合?

意图:
 允许一个对象在其内部状态改变时改变它的行为。从而使对象看起来似乎修改了其行为。  ------《设计模式》GOF
结构图:
   
适用性:
    1.一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
2.一个操作中含有庞大的多分支的等条件语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常,有多个操作包含这一相同的条件结构。State模式将每一个分支放入一个独立的类中。这使得你可根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。

代码实现:
   


  
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
    {
      
getreturn account; }
      
set{ account = value; }
    }

    
public double Balance
    {
      
getreturn 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.0this);
    }

    
// Properties
    public double Balance
    {
      
getreturn state.Balance; }
    }

    
public State State
    {
      
getreturn 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);
    }
  }
结果:
   
State模式的几个要点:
    1.State模式将所有一个特定状态相关的行为都放入一个State的子类对象中,在对象状态切换时,切换相应的对象;但同时维持State的接口,这样实现了具体操作与状态转换之间的解耦。
    2.为不同的状态引入不同的对象使得状态转换变得更加明确,而且可以保证不会出现状态不一致的情况,因为转换是原子性的----即要么彻底转换过来,要么不转换。
    3.如果State对象没有实例变量,那么各个上下文可以共享 同一个State对象,从而节省对象开销。
posted on 2007-09-29 14:38  王晓成  阅读(7757)  评论(1编辑  收藏  举报