2014-01-24 103 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類中使用規範模式。