2014-01-24 4 views
2

У меня есть программа банковского счета. Каждая учетная запись может находиться в состоянии начального состояния или доверенной учетной записи (в настоящее время). В будущем могут быть добавлены новые государства. Проценты не выплачиваются, если они находятся в исходном состоянии. Но 9% процентов выплачивается, если он находится в состоянии доверенной учетной записи.Уменьшение сцепления в шаблоне состояния

Следующий код работает. Но в методе ChangeState() существует жесткая связь. InitialAccountState должен знать о существовании TrustedAccountedState .. И если мы добавим новое состояние с именем VeteranAccountedState, метод ChangeState() необходимо переписать в классе InitialAccountState.

Каков наилучший способ .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); 
     } 
    } 

КЛИЕНТ

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 отделены друг от друга, и теперь, если вам нужно добавить больше состояний, есть только один класс, который должен быть обновлен. Затем классам AccountState не нужно было сохранять состояние, а просто определяло бы поведение, то есть, как должен вести себя Депозит или PayInterest, если ваша учетная запись, в которой находится данное состояние. Вы все еще можете использовать шаблон спецификации в классе statechanger.

Смежные вопросы