2014-01-24 61 views
2

我有一个银行账户程序。每个账户可以处于初始状态或可信账户状态(目前)。未来可能会增加新的州。如果处于初始状态,则不支付利息。但如果它在可信账户状态,则支付9%的利息。减少状态模式中的耦合

以下代码有效。但ChangeState()方法中存在紧密耦合。 InitialAccountState需要知道TrustedAccountedState的存在。如果我们添加一个名为VeteranAccountedState的新状态,则需要在InitialAccountState类中重写ChangeState()方法。

什么是最好的.Net 4.0的方式来减少这种耦合?

状态模式

状态模式允许一个对象的状态在任何给定的时刻,实际上改变了其行为改变。

状态变化的顺序是预先定义的时,耦合不是状态模式的问题。例如,交通信号灯将总是从绿 - 黄 - 红变化。在这种情况下,耦合不是问题 - 绿色可以肯定它在下一步中总是处于黄色状态。请参阅Analysis Of State Machine Pattern

抽象状态

abstract class AccountState 
    { 
     // Properties 
     public BankAccount Account { get; set; } 
     public double Balance { get; set; } 

     protected double interest; 
     protected double lowerLimit; 
     protected double upperLimit; 

     public abstract void Deposit(double amount); 
     public abstract void PayInterest(); 
    } 

混凝土

class InitialAccountState : AccountState 
    { 
     public InitialAccountState(AccountState state) :this(state.Balance, state.Account) 
     { 

     } 

     public InitialAccountState(double balance, BankAccount account) 
     { 
      this.Balance = balance; 
      this.Account = account; 
      Initialize(); 
     } 

     private void Initialize() 
     { 
      lowerLimit = 0.0; 
      upperLimit = 1000.0; 
     } 

     public override void Deposit(double amount) 
     { 
      Balance += amount; 
      ChangeState(); 
     } 

     public override void PayInterest() 
     { 
      throw new Exception("No Interest Allowed"); 
     } 

     private void ChangeState() 
     { 
      if (Balance > upperLimit) 
      { 
       Account.State = new TrustedAccountedState(this); 
      } 
     } 
    } 

    class TrustedAccountedState : AccountState 
    { 
     public TrustedAccountedState(AccountState state): this(state.Balance, state.Account) 
     { 
     } 

     public TrustedAccountedState(double balance, BankAccount account) 
     { 
      this.Balance = balance; 
      this.Account = account; 
      Initialize(); 
     } 

     private void Initialize() 
     { 
      interest = 0.05; 
      lowerLimit = 1000.0; 
      upperLimit = 10000000.0; 
     } 

     public override void Deposit(double amount) 
     { 
      Balance += amount; 
      ChangeState(); 
     } 

     public override void PayInterest() 
     { 
      Balance += interest * Balance; 
      ChangeState(); 
     } 

     private void ChangeState() 
     { 
      if (Balance < lowerLimit) 
      { 
       Account.State = new InitialAccountState(this); 
      } 
     } 
    } 

背景

class BankAccount 
    { 
     // Properties 
     public AccountState State { get; set; } 

     public double Balance 
     { 
      get { return State.Balance; } 
     } 


     // Constructor 
     public BankAccount(string owner) 
     { 
      this.State = new InitialAccountState(0.0, this); 
     } 

     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}", this.State.GetType().Name); 
      Console.WriteLine(""); 
     } 

     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); 
     } 
    } 

CLIENT

class Program 
    { 
     static void Main(string[] args) 
     { 
      BankAccount account = new BankAccount("Jim Johnson"); 

      account.Deposit(500.0); 
      account.Deposit(300.0); 
      account.Deposit(550.0); 
      account.PayInterest(); 

      Console.ReadKey(); 
     } 
} 

参考

  1. Analysis Of State Machine Pattern
  2. Is the State Design pattern scalable ?
  3. State Design Pattern
  4. Implementing the Specification Pattern in .NET
  5. Is the Specification Pattern obsolete?
  6. Specification pattern in C#
  7. Specifications in C# 3.0
  8. LINQ Expression Trees and the Specification Pattern
+1

您可能想要考虑规范模式:http://en.wikipedia.org/wiki/Specification_pattern –

回答

4

我状态的变化重构出另一个类如服务类,其职责是了解如何改变状态,从而反转的依赖和消除状态之间的紧密耦合。 所以我会更改抽象类,以便受保护的属性可以访问。

abstract class AccountState 
{ 
    // Properties 
    public BankAccount Account { get; set; } 
    public double Balance { get; set; } 

    internal double interest; 
    internal double lowerLimit; 
    internal double upperLimit; 

    public abstract void Deposit(double amount); 
    public abstract void PayInterest(); 
} 

添加StateChanger类...

public class StateChanger(){ 
    public AccountState ChangeState(AccountState state){ 
     if((state is InitialAccountState) && (state.Balance > state.upperLimit)){ 
      return new TrustedAccountedState(state); 
     } 
     if((state is TrustedAccountedState) && (state.Balance < state.lowerLimit)) 
     { 
      return new InitialAccountState(state); 
     } 
     return state; 
    } 
} 

从AccountState类中删除依赖

class InitialAccountState : AccountState 
{ 
    public InitialAccountState(AccountState state) :this(state.Balance, state.Account) 
    { 

    } 

    public InitialAccountState(double balance, BankAccount account) 
    { 
     this.Balance = balance; 
     this.Account = account; 
     Initialize(); 
    } 

    private void Initialize() 
    { 
     lowerLimit = 0.0; 
     upperLimit = 1000.0; 
    } 

    public override void Deposit(double amount) 
    { 
     Balance += amount; 
    } 

    public override void PayInterest() 
    { 
     throw new Exception("No Interest Allowed"); 
    } 

} 

class TrustedAccountedState : AccountState 
{ 
    public TrustedAccountedState(AccountState state): this(state.Balance, state.Account) 
    { 
    } 

    public TrustedAccountedState(double balance, BankAccount account) 
    { 
     this.Balance = balance; 
     this.Account = account; 
     Initialize(); 
    } 

    private void Initialize() 
    { 
     interest = 0.05; 
     lowerLimit = 1000.0; 
     upperLimit = 10000000.0; 
    } 

    public override void Deposit(double amount) 
    { 
     Balance += amount; 
    } 

    public override void PayInterest() 
    { 
     Balance += interest * Balance; 
    } 

} 

然后你BackAccount该类行为像一个控制器,它看起来像

class BankAccount 
    { 

    // Properties 
    public AccountState State { get; set; } 
    private StateChanger stateChanger; 

    public double Balance 
    { 
     get { return State.Balance; } 
    } 


    // Constructor 
    public BankAccount(string owner,StateChanger stateChanger) 
    { 
     this.State = new InitialAccountState(0.0, this); 
     this.stateChanger = stateChanger; 
    } 

    public void Deposit(double amount) 
    { 
     State.Deposit(amount); 
     State = stateChanger.ChangeState(State); 

     Console.WriteLine("Deposited {0:C} --- ", amount); 
     Console.WriteLine(" Balance = {0:C}", this.Balance); 
     Console.WriteLine(" Status = {0}", this.State.GetType().Name); 
     Console.WriteLine(""); 
    } 

    public void PayInterest() 
    { 
     State.PayInterest(); 
     State = stateChanger.ChangeState(State);   
     Console.WriteLine("INTEREST PAID --- "); 
     Console.WriteLine(" Balance = {0:C}", this.Balance); 
     Console.WriteLine(" Status = {0}\n", this.State.GetType().Name); 
    } 
} 

和主

class Program 
    { 
     static void Main(string[] args) 
     { 
      StateChanger stateChanger = new StateChanger(); 
      BankAccount account = new BankAccount("Jim Johnson",stateChanger); 

      account.Deposit(500.0); 
      account.Deposit(300.0); 
      account.Deposit(550.0); 
      account.PayInterest(); 

      Console.ReadKey(); 
     } 
} 

通过分离出来管理国家的关注,AccountState类是彼此分离的,现在如果您需要添加更多的国家有刚1类,需要更新。然后AccountState类不需要保持状态,而是只定义行为,即如果您的账户存在给定状态,Deposit或PayInterest应该如何表现。您仍然可以在statechanger类中使用规范模式。