understanding and implementing state pattern in c#

11
Search for articles, questions, tips Q&A forums lounge articles Rahul Rajat Singh, 12 Nov 2012 CPOL Rate: Understanding and Implementing State Pattern in C# This article describes what is state pattern, when could we find state pattern useful and how to have a rudimentary implementation of state pattern in C#. Is your email address OK? You are signed up for our newsletters but your email address is either unconfirmed, or has not been reconfirmed in a long time. Please click here to have a confirmation email sent so we can confirm your email address and start sending you newsletters again. Alternatively, you can update your subscriptions. Download sample - 12.4 KB Introduction This article describes what is state pattern, when could we find state pattern useful and how to have a rudimentary implementation of state pattern in C#. Background There are times when we find some scenarios in our application when we need to maintain the state of a sub system. This state needs to be changed based on some conditions and/or user actions. One way to keep track of such states is by using the conditional logic in code. Using conditional logic will get us the desired result but that would result in a code that is less understandable and is harder to maintain. Also, if we need to add more states in the system then that is very difficult and could create problems in existing system too. To tackle such problems efficiently, GoF suggest use of State pattern. GoF defines state pattern as "Allow an object to alter its behavior when its internal state changes. The object will appear to change its class." 4.88 (19 votes) 11,826,143 members (62,984 online) 326 Sign out mnacho2

Upload: kukuduxu

Post on 03-Dec-2015

221 views

Category:

Documents


4 download

DESCRIPTION

How to understand and implement the state pattern in c#

TRANSCRIPT

Page 1: Understanding and Implementing State Pattern in C#

Search for articles, questions, tipsQ&A forums loungearticles

Rahul Rajat Singh, 12 Nov 2012 CPOL Rate:

Understanding and Implementing State Patternin C#

This article describes what is state pattern, when could we find state pattern useful and how to have a rudimentaryimplementation of state pattern in C#.

Is your email address OK? You are signed up for our newsletters but your email address is eitherunconfirmed, or has not been reconfirmed in a long time. Please click here to have a confirmationemail sent so we can confirm your email address and start sending you newsletters again.

Alternatively, you can update your subscriptions.

Download sample - 12.4 KB

IntroductionThis article describes what is state pattern, when could we find state pattern useful and how to have a rudimentaryimplementation of state pattern in C#.

BackgroundThere are times when we find some scenarios in our application when we need to maintain the state of a sub system.This state needs to be changed based on some conditions and/or user actions. One way to keep track of such states isby using the conditional logic in code.

Using conditional logic will get us the desired result but that would result in a code that is less understandable and isharder to maintain. Also, if we need to add more states in the system then that is very difficult and could createproblems in existing system too.

To tackle such problems efficiently, GoF suggest use of State pattern. GoF defines state pattern as "Allow an object toalter its behavior when its internal state changes. The object will appear to change its class."

   4.88 (19 votes)

11,826,143 members (62,984 online) 326   Sign out mnacho2

Page 2: Understanding and Implementing State Pattern in C#

It can also be thought of as an object oriented state machine. Let us see the major classes in this pattern.

Context: This is the actual object who is accessed by the client. The state of this object needs to be tracked.

State: This is an interface or abstract class that defines the common behavior associated with all the possiblestates of the Context.

ConcreteState: This class represent a state of the Context. Each state will be represented as one concreteclass.

Using the codeLet us try to implement a small example to understand the state pattern in detail. Let us try to implement thesoftware for a dummy ATM machine. The ATM machine is with us and the Bank has decided to have 3 states for thismachine.

1. No card in the machine2. Card inserted and has been validated3. Cash withdrawn

Now first let us see how we would implement this solution without using the state pattern. We would create a classfor the ATM and then have the state of the ATM maintained locally. Following code snippet shows how we couldimplement such ATM class and keep the state of the machine inside the object itself.

Hide   Shrink   Copy Code

class NoStateATM{ public enum MACHINE_STATE { NO_CARD, CARD_VALIDATED, CASH_WITHDRAWN, }

private MACHINE_STATE currentState = MACHINE_STATE.NO_CARD; private int dummyCashPresent = 1000;

public string GetNextScreen() { switch (currentState) { case MACHINE_STATE.NO_CARD: // Here we will get the pin validated return GetPinValidated(); break; case MACHINE_STATE.CARD_VALIDATED: // Lets try to withdraw the money

Page 3: Understanding and Implementing State Pattern in C#

return WithdrawMoney(); break; case MACHINE_STATE.CASH_WITHDRAWN: // Lets let the user go now return SayGoodBye(); break; } return string.Empty; }

private string GetPinValidated() { Console.WriteLine("Please Enter your Pin"); string userInput = Console.ReadLine();

// lets check with the dummy pin if (userInput.Trim() == "1234") { currentState = MACHINE_STATE.CARD_VALIDATED; return "Enter the Amount to Withdraw"; } // Show only message and no change in state return "Invalid PIN"; }

private string WithdrawMoney() { string userInput = Console.ReadLine();

int requestAmount; bool result = Int32.TryParse(userInput, out requestAmount);

if (result == true) { if (dummyCashPresent < requestAmount) { // Show only message and no change in state return "Amount not present"; }

dummyCashPresent -= requestAmount; currentState = MACHINE_STATE.CASH_WITHDRAWN;

return string.Format(@"Amount of {0} has been withdrawn. Press Enter to proceed", requestAmount); }

// Show only message and no change in state return "Invalid Amount"; }

private string SayGoodBye() { currentState = MACHINE_STATE.NO_CARD; return string.Format("Thanks you for using us, Amount left in ATM: {0}", dummyCashPresent.ToString()); }}

Page 4: Understanding and Implementing State Pattern in C#

Now when we run the class we can see that this works perfectly from the functionality perspective.

The problem will come when we need to add more states. Whenever we need to add more states to this ATMmachine we need to open up the ATM machine code and then add more logic inside this class itself which is a clearvioloation of Open-Close priciple. Also since we have all that state managed in form of conditional logic, there aresome possibilities that changing code to add new states will break existing functionality too i.e. this way is more errorprone.

So, what would be the better way to do this? The better way to do this is by implementing the same solution usingstate pattern. The only thing that we need to do is "encapsulate what varies". So we will go ahead and pull the staterelated logic from the ATM class and create seprate classes for each state.

Let us start by modifying the ATM class so that it will contain no state related information. It will only keep an handleto the object which keeps track of its state. 

Hide   Copy Code

public class ATM{ public ATMState currentState = null;

public ATM() { currentState = new NoCardState(1000, this); }

public void StartTheATM() { while (true) { Console.WriteLine(currentState.GetNextScreen()); } }}

Now the member variable in this class that is being used as the handle to the state is just an abstract class. This classwill point to the actual concrete implementation of state i.e. the real state of the machine dynamically.

Hide   Copy Code

Page 5: Understanding and Implementing State Pattern in C#

public abstract class ATMState{ private ATM atm;

public ATM Atm { get { return atm; } set { atm = value; } } private int dummyCashPresent = 1000;

public int DummyCashPresent { get { return dummyCashPresent; } set { dummyCashPresent = value; } }

public abstract string GetNextScreen();}

And finally we have all the concrete classes, each for one state of the ATM machine. Lets look at all the state classesnow

The class for NO_CARD state:

Hide   Shrink   Copy Code

class NoCardState : ATMState{ // This constructor will create new state taking values from old state public NoCardState(ATMState state) :this(state.DummyCashPresent, state.Atm) { }

// this constructor will be used by the other one public NoCardState(int amountRemaining, ATM atmBeingUsed) { this.Atm = atmBeingUsed; this.DummyCashPresent = amountRemaining; }

public override string GetNextScreen() { Console.WriteLine("Please Enter your Pin"); string userInput = Console.ReadLine();

// lets check with the dummy pin if (userInput.Trim() == "1234") { UpdateState(); return "Enter the Amount to Withdraw"; }

// Show only message and no change in state return "Invalid PIN"; }

Page 6: Understanding and Implementing State Pattern in C#

private void UpdateState() { Atm.currentState = new CardValidatedState(this); }}

The class for CARD_VALIDATED state:

Hide   Shrink   Copy Code

class CardValidatedState : ATMState{ // This constructor will create new state taking values from old state public CardValidatedState(ATMState state) :this(state.DummyCashPresent, state.Atm) { }

// this constructor will be used by the other one public CardValidatedState(int amountRemaining, ATM atmBeingUsed) { this.Atm = atmBeingUsed; this.DummyCashPresent = amountRemaining; }

public override string GetNextScreen() { string userInput = Console.ReadLine();

int requestAmount; bool result = Int32.TryParse(userInput, out requestAmount);

if (result == true) { if (this.DummyCashPresent < requestAmount) { // Show only message and no change in state return "Amount not present"; }

this.DummyCashPresent -= requestAmount; UpdateState();

return string.Format(@"Amount of {0} has been withdrawn. Press Enter to proceed", requestAmount); }

// Show only message and no change in state return "Invalid Amount"; }

private void UpdateState() { Atm.currentState = new NoCashState(this); }}

Page 7: Understanding and Implementing State Pattern in C#

The class for CASH_WITHDRAWN state: 

Hide   Copy Code

class CashWithdrawnState : ATMState{ // This constructor will create new state taking values from old state public CashWithdrawnState(ATMState state) :this(state.DummyCashPresent, state.Atm) { }

// this constructor will be used by the other one public CashWithdrawnState(int amountRemaining, ATM atmBeingUsed) { this.Atm = atmBeingUsed; this.DummyCashPresent = amountRemaining; }

public override string GetNextScreen() { UpdateState(); return string.Format("Thanks you for using us, Amount left in ATM: {0}", this.DummyCashPresent.ToString()); }

private void UpdateState() { Atm.currentState = new NoCardState(this); }}

Now with this design we are atually achieving the same functionality that we were achieving in the earlier example.

This sure looks like more code but this approach is less error prone and using this approach the ATM class will needno modification. So if we need to add a new state then there will be minimal impact on code of existing state classes.

So if I need to add a state for NO_CASH in this system, I just have to add a new concrete class that and hook it withthe system. 

Hide   Shrink   Copy Code

class NoCashState : ATMState{ // This constructor will create new state taking values from old state public NoCashState(ATMState state) :this(state.DummyCashPresent, state.Atm) { }

// this constructor will be used by the other one public NoCashState(int amountRemaining, ATM atmBeingUsed) { this.Atm = atmBeingUsed; this.DummyCashPresent = amountRemaining; }

public override string GetNextScreen() { Console.WriteLine("ATM is EMPTY");

Page 8: Understanding and Implementing State Pattern in C#

Console.ReadLine(); return string.Empty; }

private void UpdateState() { // nothing here as someone will have to fill in cash and then // restart the atm, once restarted it will be in no card state }}

And a minor modification in the UpdateState function of the CardValidatedState class. 

Hide   Copy Code

private void UpdateState(){ if (this.DummyCashPresent == 0) { Atm.currentState = new NoCashState(this); } else { Atm.currentState = new CashWithdrawnState(this); }}

Now let us test this system.

Before wrapping up let us look at the clas diagram of our application and compare it with the class diagram of GoF. 

Page 9: Understanding and Implementing State Pattern in C#

Point of interest In this article we tried to get an overviwe of the state pattern and when could it be used. We also implemented assmall application that contains a rudimentaty implementation of state pattern.

History05 November 2012: First version.

LicenseThis article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

EMAIL TWITTER

Page 10: Understanding and Implementing State Pattern in C#

You may also be interested in...

Understanding State Patternin C++

DevOps For Dummies

Understanding andImplementing DecoratorPattern in C#

Is SQL Server killing yourapplication’s performance?

Understanding JavaScriptObject Creation Patterns

Add HTML5 DocumentViewer to ASP.NET MVC 5Project

Rahul Rajat Singh Architect

India

I Started my Programming career with C++. Later got a chance to develop Windows Form applications using C#.Currently using C#, ASP.NET & ASP.NET MVC to create Information Systems, e-commerce/e-governance Portals andData driven websites.

My interests involves Programming, Website development and Learning/Teaching subjects related to ComputerScience/Information Systems. IMO, C# is the best programming language and I love working with C# and otherMicrosoft Technologies.

Microsoft Certified Technology Specialist (MCTS): Web Applications Development with Microsoft .NETFramework 4Microsoft Certified Technology Specialist (MCTS): Accessing Data with Microsoft .NET Framework 4Microsoft Certified Technology Specialist (MCTS): Windows Communication Foundation Development withMicrosoft .NET Framework 4

If you like my articles, please visit my website for more: www.rahulrajatsingh.com[^]

Microsoft MVP 2015

Page 11: Understanding and Implementing State Pattern in C#

Permalink | Advertise | Privacy | Terms of Use | Mobile Web01 | 2.8.151018.1 | Last Updated 12 Nov 2012 Select Language ▼

Article Copyright 2012 by Rahul Rajat SinghEverything else Copyright © CodeProject, 1999-2015

Layout: fixed |fluid

Add a Comment or Question    Search Comments   Go

 

Comments and Discussions

First Prev Next

Refresh 1

General    News    Suggestion    Question    Bug    Answer    Joke    Rant    Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Do you know Stateless? Frank Lindecke 25-Sep-14 14:31

My vote of 5 Torsten Tiedt 25-Jul-14 22:07

Good article - not so good pattern Torsten Tiedt 25-Jul-14 22:06

My vote of 5 Gena H 25-Mar-14 13:34

Nice Komil 19-Dec-13 18:40

My vote of 5 Member 10033741 7-May-13 9:23

Why he has instantiated? Ekaitz Hernandez 13-Nov-12 0:37

Re: Why he has instantiated? Rahul Rajat Singh 15-Nov-12 4:08