State Design Pattern
By Peter Bromberg
The state of an object is represented by the values of its instance variables. A client can change the state of an object by making property or method calls which in turn change the instance variables. These types of objects are called stateful objects. State is frequently a core concept in complex systems, such as, stock market trading systems.
using System;
namespace Patterns
{
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.ReadKey();
}
}
/// <summary>
/// The 'State' abstract class
/// </summary>
abstract class State
{
protected double interest;
protected double lowerLimit;
protected double upperLimit;
// Gets or sets the account
public Account Account { get; set; }
// Gets or sets the balance
public double Balance { get; set; }
public abstract void Deposit(double amount);
public abstract void Withdraw(double amount);
public abstract void PayInterest();
}
/// <summary>
/// A 'ConcreteState' class
/// <remarks>
/// Red state indicates account is overdrawn
/// </remarks>
/// </summary>
class RedState : State
{
private double _serviceFee;
// Constructor
public RedState(State state)
{
Balance = state.Balance;
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);
}
}
}
/// <summary>
/// A 'ConcreteState' class
/// <remarks>
/// Silver state is non-interest bearing state
/// </remarks>
/// </summary>
class SilverState : State
{
// Overloaded constructors
public SilverState(State state) :
this(state.Balance, state.Account)
{
}
public SilverState(double balance, Account account)
{
Balance = balance;
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);
}
}
}
/// <summary>
/// A 'ConcreteState' class
/// <remarks>
/// Gold incidates interest bearing state
/// </remarks>
/// </summary>
class GoldState : State
{
// Overloaded constructors
public GoldState(State state)
:
this(state.Balance, state.Account)
{
}
public GoldState(double balance, Account account)
{
Balance = balance;
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);
}
}
}
/// <summary>
/// The 'Context' class
/// </summary>
class Account
{
private string _owner;
// Constructor
public Account(string owner)
{
// New accounts are 'Silver' by default
this._owner = owner;
this.State = new SilverState(0.0, this);
}
// Gets the balance
public double Balance
{
get
{ return State.Balance; }
}
// Gets or sets state
public State State { get; set; }
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 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 Design Pattern (732 Views)