The State pattern allows an object to change its behavior when its internal state changes. This pattern can be observed in a vending machine. Vending machines have states based on the inventory, amount of currency deposited, the ability to make change, the item selected, etc. When currency is deposited and a selection is made, a vending machine will either deliver a product and no change, deliver a product and change, deliver no product due to insufficient currency on deposit, or deliver no product due to inventory depletion.
The frequency of use of State Pattern is Medium but is very useful and frequently used Telecoms Protocols implementation.
The frequency of use of State Pattern is Medium but is very useful and frequently used Telecoms Protocols implementation.
Example as follows:
//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//State is part of Behavioral Patterns
//Behavioral Patterns deal with dynamic interactions among societies of classes and objects
//State allows an object to alter its behavior when its internal state changes.
// The object will appear to change its class
//We will take an example Bank card where depending on the deposit the customers status changes
#include<iostream>
#include<string>
#include "main.h"
Account* State::GetAccount(void)
{
return account_;
}
void State::SetAccount(Account* account)
{
account_ = account;
}
double State::GetBalance(void)
{
return balance_;
}
void State::SetBalance(double balance)
{
balance_ = balance;
}
string State::GetStateName(void)
{
return stateName_;
}
RedState::RedState(State* state)
{
this->balance_ = state->GetBalance();
this->account_ = state->GetAccount();
Initialise();
}
void RedState::Deposit(double amount)
{
balance_ += amount;
StateChangeCheck();
}
void RedState::Withdraw(double amount)
{
double newAmount = amount + serviceFee_;
if(balance_ - newAmount < lowerLimit_)
cout<<"No funds available for withdrawal!"<<endl;
else
balance_ -= newAmount;
}
void RedState::PayInterest()
{
//No interest is paid
}
void RedState::StateChangeCheck()
{
if (balance_ > upperLimit_)
{
account_->SetState(reinterpret_cast<State*>(new SilverState(this)));
delete this;
return;
}
}
void RedState::Initialise()
{
stateName_ = "Red";
//Should come from a data source
interest_ = 0.0;
lowerLimit_ = -100.0;
upperLimit_ = 0.0;
serviceFee_ = 15.0;
}
SilverState::SilverState(State* state)
{
this->balance_ = state->GetBalance();
this->account_ = state->GetAccount();
Initialise();
}
SilverState::SilverState(double balance, Account* account)
{
this->balance_ = balance;
this->account_ = account;
Initialise();
}
void SilverState::Deposit(double amount)
{
balance_ += amount;
StateChangeCheck();
}
void SilverState::Withdraw(double amount)
{
balance_ -= amount;
StateChangeCheck();
}
void SilverState::PayInterest()
{
balance_ = balance_ * interest_;
StateChangeCheck();
}
void SilverState::StateChangeCheck()
{
if (balance_ < lowerLimit_)
{
account_->SetState(reinterpret_cast<State*>(new RedState(this)));
delete this;
return;
}
else if (balance_ > upperLimit_)
{
account_->SetState(reinterpret_cast<State*>(new GoldState(this)));
delete this;
return;
}
}
void SilverState::Initialise()
{
stateName_ = "Silver";
//Should come from a data source
interest_ = 1.0;
lowerLimit_ = 0.0;
upperLimit_ = 1000.0;
}
GoldState::GoldState(State* state)
{
this->balance_ = state->GetBalance();
this->account_ = state->GetAccount();
Initialise();
}
void GoldState::Deposit(double amount)
{
balance_ += amount;
StateChangeCheck();
}
void GoldState::Withdraw(double amount)
{
balance_ -= amount;
StateChangeCheck();
}
void GoldState::PayInterest()
{
balance_ = balance_ * interest_;
StateChangeCheck();
}
void GoldState::StateChangeCheck()
{
if (balance_ < 0.0)
{
account_->SetState(reinterpret_cast<State*>(new RedState(this)));
delete this;
return;
}
else if (balance_ < lowerLimit_)
{
account_->SetState(reinterpret_cast<State*>(new SilverState(this)));
delete this;
return;
}
else if (balance_ > upperLimit_)
{
cout<<"Your account is too big now. Please consider using Swiss banks"<<endl;
}
}
void GoldState::Initialise()
{
stateName_ = "Gold";
//Should come from a data source
interest_ = 5.0;
lowerLimit_ = 1000.0;
upperLimit_ = 10000000.0;
}
Account::Account(string owner):owner_(owner)
{
state_ = reinterpret_cast<State*>(new SilverState(0.0, this)); //default
}
Account::~Account()
{
delete state_;
}
double Account::GetBalance(void)
{
return state_->GetBalance();
}
void Account::Deposit(double amount)
{
state_->Deposit(amount);
cout<<"Deposited $"<<amount<<endl;
cout<<"Balance $"<<GetBalance()<<endl;
cout<<"Status "<<state_->GetStateName()<<endl;
cout<<"\n";
}
void Account::Withdraw(double amount)
{
state_->Withdraw(amount);
cout<<"Withdrew $"<<amount<<endl;
cout<<"Balance $"<<GetBalance()<<endl;
cout<<"Status "<<state_->GetStateName()<<endl;
cout<<"\n";
}
void Account::PayInterest()
{
state_->PayInterest();
cout<<"Interest Paid --------"<<endl;
cout<<"Balance $"<<GetBalance()<<endl;
cout<<"Status "<<state_->GetStateName()<<endl;
cout<<"\n";
}
void Account::SetState(State* state)
{
state_ = state;
}
State* Account::GetState(void)
{
return state_;
}
//The Main method
int main()
{
Account* account = new Account("Dr. Who");
account->Withdraw(10.00);
account->Withdraw(30.00);
account->Withdraw(70.00);
account->Deposit(234.00);
account->Deposit(5000.00);
account->Withdraw(5200.00);
account->Deposit(1500.00);
account->Deposit(1.00);
account->Withdraw(1200.00);
delete account;
return 0;
}
The output is as follows:
http://www.dofactory.com/Patterns/PatternState.aspx