In continuation with the series on design pattern, I am currently going
through Behavioral Patterns. Today I will write about the State Pattern.
You can read about the other patterns from the following links
Strategy
Pattern
You can read about the Structural patterns
here .
You can read about the Creational patterns
here .
State pattern in essence is a dynamic version of the strategy pattern,
meaning, when the sate inside an object is changed, it could change its
behavior.
namespace PatternsConsole
{
class StatePattern
{
interface IState
{
void Deposit (
double amount );
void Withdraw (
double amount );
double Balance { get ; set ; }
Account Account { get ; set ; }
}
// State 1
class InsufficientState : IState
{
public InsufficientState (
double balance ,
Account account )
{
Balance = balance ;
Account = account ;
}
public void Deposit (
double amount )
{
Balance += amount ;
CheckState ();
}
public void Withdraw (
double amount )
{
Balance -= amount ;
Console . WriteLine ( "Insufficient fund" );
}
private void CheckState ()
{
if ( Balance > 100 )
{
Account . State = new NormalState (
Balance ,
Account );
}
else if ( Balance > 300 )
{
Account . State = new GoldState (
Balance ,
Account );
}
}
public double Balance { get ; set ; }
public Account Account { get ; set ; }
}
// State 2
class NormalState : IState
{
public NormalState (
double balance ,
Account account )
{
Balance = balance ;
Account = account ;
}
public void Deposit (
double amount )
{
Balance += amount ;
CheckState ();
}
public void Withdraw (
double amount )
{
Balance -= amount ;
CheckState ();
}
private void CheckState ()
{
if ( Balance < 100 )
{
Account . State = new InsufficientState (
Balance ,
Account );
}
else if ( Balance > 300 )
{
Account . State = new GoldState (
Balance ,
Account );
}
}
public double Balance { get ; set ; }
public Account Account { get ; set ; }
}
// State 3
class GoldState : IState
{
public GoldState (
double balance ,
Account account )
{
Balance = balance ;
Account = account ;
}
public void Deposit (
double amount )
{
Balance += amount ;
CheckState ();
}
public void Withdraw (
double amount )
{
Balance -= amount ;
CheckState ();
}
private void CheckState ()
{
if ( Balance < 100 )
{
Account . State = new InsufficientState (
Balance ,
Account );
}
else if ( Balance < 300 )
{
Account . State = new NormalState (
Balance ,
Account );
}
}
public double Balance { get ; set ; }
public Account Account { get ; set ; }
}
// Context
class Account
{
public IState State { set ; get ; }
// Construcstor
public Account ()
{
State = new NormalState (
0 ,
this );
}
public void Deposit (
double amount )
{
State . Deposit ( amount );
Console . WriteLine (
"Deposited {0:C} " ,
amount );
Console . WriteLine (
" Balance = {0:C}" ,
State . Balance );
Console . WriteLine (
" Status = {0}" ,
State . GetType (). Name );
Console . WriteLine ( "" );
}
public void Withdraw (
double amount )
{
State . Withdraw ( amount );
Console . WriteLine (
"Withdrew {0:C} " ,
amount );
Console . WriteLine (
" Balance = {0:C}" ,
State . Balance );
Console . WriteLine (
" Status = {0}\n" ,
State . GetType (). Name );
}
}
static void Main ()
{
var account = new Account ();
account . Deposit ( 100 );
account . Deposit ( 100 );
account . Deposit ( 300 );
account . Withdraw ( 200 );
account . Withdraw ( 200 );
account . Withdraw ( 100 );
// Output:
// Deposited $100.00
// Balance = $100.00
// Status = NormalState
// Deposited $100.00
// Balance = $200.00
// Status = NormalState
// Deposited $300.00
// Balance = $500.00
// Status = GoldState
// Withdrew $200.00
// Balance = $300.00
// Status = GoldState
// Withdrew $200.00
// Balance = $100.00
// Status = NormalState
// Withdrew $100.00
// Balance = $0.00
// Status = InsufficientState
Console . Read ();
}
}
}
As you can see in the example, the behavior of our code is changing
based on the state which internally is changed based on the amount
balance. We can use the state pattern when we have objects that may
change their behavior at runtime based on some context or when the
objects are becoming complex with many conditional branches.
In my next post I will be writing about the Template Method Pattern
Comments