Wednesday, February 9, 2011

Behavioral Patterns - State Pattern

Definition

An object's behavior change is represented by its member classes, which share the same super class. 

Intent

  • Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
  • An object-oriented state machine
  • wrapper + polymorphic wrappee + collaboration

Problem

A monolithic object’s behavior is a function of its state, and it must change its behavior at run-time depending on that state. Or, an application is characterixed by large and numerous case statements that vector flow of control based on the state of the application.

Where to use & benefits

  • Need to control many states without using if-else or switch statements.
  • Use a class to represent a state, not a constant or something else.
  • Every state has to act in a similar manner.
  • Every state must be a subclass of the same super class.
  • Simplify and clarify the program.
  • Related patterns include
    • Flyweight, which explains when and how a state object can be shared.
    • Singleton which is often used with state pattern to ensure some state change is shared with class itself, not instances of the class. 


    Example

    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.
    State example 


    Why read if you can watch?

    Watch design patterns video tutorial
    Read full article
    1. Create a State class hierarchy
    2. The State base class has a single method void pull(Chain wrapper) The method can be abstract, or, it can contain default behavior
    3. Create a State derived class for each condition in the if-then-else statement
    4. Move each println() statement to the pull() method of its appropriate class
    5. Make the Chain class a “wrapper” class that models the state machine abstraction
    6. The Chain class maintains a “current” State object
    7. All client requests [i.e. pull()] are simply delegated to the current state object and the wrapper object’s “this” pointer is passed
    8. The Chain class needs a constructor that initializes its current state
    9. It also needs a setState() method that the State derived classes can use to change the state of the state machine
    10. Call the setState() method as necessary in each of the State derived classes pull() methods
    import java.io.*;
    
    class Chain {
        private int state;
    
        public Chain()     { state = 0; }
        public void pull() {
            if (state == 0) {
                state = 1;
                System.out.println( "   low speed" );
            } else if (state == 1) {
                state = 2;
                System.out.println( "   medium speed" );
            } else if (state == 2) {
                state = 3;
                System.out.println( "   high speed" );
            } else {
                state = 0;
                System.out.println( "   turning off" );
    }   }   }
    
    public class StateDisc {
        public static void main( String[] args ) throws IOException {
            InputStreamReader is = new InputStreamReader( System.in );
            int ch;
            Chain chain = new Chain();
            while (true) {
                System.out.print( "Press 'Enter'" );
                ch = is.read();    ch = is.read();
                chain.pull();
    }   }   }
    Press 'Enter' low speed Press 'Enter' medium speed Press 'Enter' high speed Press 'Enter' turning off Press 'Enter' low speed Press 'Enter' medium speed Press 'Enter' high speed Press 'Enter' turning off
    Example : 2

    State in Java

    Why read if you can watch?

    Watch design patterns video tutorial
    Read full article

    State design pattern implementation

    class Chain {
        private State current;
    
        public Chain()                  { current = new Off(); }
        public void setState( State s ) { current = s; }
        public void pull()              { current.pull( this ); }
    }
    
    abstract class State {
        public void pull( Chain wrapper ) {
            wrapper.setState( new Off() );
            System.out.println( "   turning off" );
    }   }
    
    class Off extends State {
        public void pull( Chain wrapper ) {
            wrapper.setState( new Low() );
            System.out.println( "   low speed" );
    }   }
    
    class Low extends State {
        public void pull( Chain wrapper ) {
            wrapper.setState( new Medium() );
            System.out.println( "   medium speed" );
    }   }
    
    class Medium extends State {
        public void pull( Chain wrapper ) {
            wrapper.setState( new High() );
            System.out.println( "   high speed" );
    }   }
    
    class High extends State { }
    
    public class StateDisc {
        public static void main( String[] args ) throws IOException {
            InputStreamReader is = new InputStreamReader( System.in );
            int ch;
            Chain chain = new Chain();
            while (true) {
                System.out.print( "Press 'Enter'" );
                ch = is.read();    ch = is.read();
                chain.pull();
    }   }   }

No comments:

Post a Comment