«

»

Dec 29

Print this Post

Design patterns: state

It’s about the time to put another design pattern post on my blog. This time I’ll write about state design pattern about which I read in the book. State pattern helps objects to control their behavior by changing their internal state. I also learnt it’s really similar to the first pattern in the book which was also mentioned by me on this blog: strategy pattern.

Book example

Imagine you’re working in B2B software company and Mighty Gumball, Inc. is asking you for help. They present you this diagram:

gumball machine flow

Mighty Gumball, Inc. gumball machine flow

and ask you to implement it in PHP. You can put everything in one class and implement it in this way:

#
class GumballMachine {
   const SOLD_OUT = 0;
   const NO_QUARTER = 1;
   const HAS_QUARTER = 2;
   const SOLD = 3;

   private $state = self::SOLD_OUT;
   private $count = 0;

   public function __construct( $count = 0 ) {
      $this->count = $count;

      if( $this->count > 0 ) {
         $this->state = self::NO_QUARTER;
      }
   }

   public function insertQuarter() {
      if( $this->state === self::HAS_QUARTER ) {
         echo "You can't insert another quarter\n";
      } else if( $this->state === self::NO_QUARTER ) {
         $this->state = self::HAS_QUARTER;
         echo "You inserted a quarter\n";
      } else if( $this->state === self::SOLD_OUT ) {
         echo "You can't insert a quarter. The machine is sold out.\n";
      } else if( $this->state === self::SOLD ) {
         echo "Please wait, we're already giving you a gumball\n";
      }
   }

   public function ejectQuarter() {
      if( $this->state === self::HAS_QUARTER ) {
         echo "Quarter returned.\n";
         $this->state = self::NO_QUARTER;
      } else if( $this->state === self::NO_QUARTER ) {
         echo "You haven't inserted a quarter.\n";
      } else if( $this->state === self::SOLD_OUT ) {
         echo "You can't eject, you haven't inserted a quarter yet.\n";
      } else if( $this->state === self::SOLD ) {
         echo "Sorry, you already turned the crank.\n";
      }
   }

   // more methods such as: turnCrank(), dispense(), __toString() and refill()
}

I shorten the example above because the rest of the methods were similar. The job we’ve done was really fast and software we created met all the requirements. It was tested and it just works. Our client is happy with the results. The job is done. Is it?

Mighty Gumball, Inc. did their own tests and they didn’t find any bugs. They are happy with our software and because it’s gone so smoothly they’d bring their machines to the next level and ask us about a small change. They want the machine to give a free gumball from time to time. Every 1 of 10 turns of the crank should give 2 gumballs. How would we implement it with our code? Well, we’d add new WINNER constant which will be new state of the machine and then… yes, then we’d have to modify all methods so they react correctly on the new WINNER state. It clearly tells us the previous design wasn’t good enough. We need to re-write the application at this point.

We should encapsulate what varies here which is the state of gumball machine. We’ll put each state’s behavior in its own class and then every state will just implement its own actions. The gumball machine will just delegate to the state object that represents the current state. This way we’ll favor composition over inheritance.

OK, let’s start with the State interface implementation:

#
interface State {
   public function insertQuarter();
   public function ejectQuarter();
   public function turnCrank();
   public function dispense();
}

It’s rather simple — we defined a method for each action done on the machine. How a concrete state class would look like? Here is an example:

#
class SoldState implements State {
   private $gumballMachine;

   public function __construct( $gumballMachine ) {
      $this->gumballMachine = $gumballMachine;
   }

   public function insertQuarter() {
      echo "Please wait, we're already giving you a gumball.\n";
   }

   public function ejectQuarter() {
      echo "Sorry, you already turned the crank.\n";
   }

   public function turnCrank() {
      echo "Turning twice doesn't get you another gumball!\n";
   }

   public function dispense() {
      $this->gumballMachine->releaseBall();
      if( $this->gumballMachine->getCount() > 0 ) {
         $this->gumballMachine->setState( 
            $this->gumballMachine->getNoQuarterState() 
         );
      } else {
         echo "Oops, out of gumballs!\n";
         $this->gumballMachine->setState( 
            $this->gumballMachine->getSoldOutState() 
         );
      }
   }
}

Implementation of other state classes is quite straight-forward. You can download all examples and you’ll notice that after implementing SoldOutState, NoQuarterState, HasQuarterState and SoldState classes, adding new methods and some changes in GumballMachine class we don’t have to touch the app.php file. It means that we made all the changes in code without changing API of GumballMachine class.

Implementing new feature such as 10% chance of getting two gumballs wasn’t hard as well. I created new WinnerState class which was really similar to SoldState and with few lines added to HasQuarterState the work was completed! A lot easier than adding another else-ifs.

Of course I could’ve implemented the new feature in already existing SoldState class but once again it was a trade-off I made. I decided to duplicate a little bit of code to keep SoldState class being responsible for only one thing. If I would’ve done it the other way imagine what could happen if the promotion ends? Or the stakes of the contest change?

OK, at the end let me introduce you the official definition of the state design pattern:

The State Pattern allows an object to alter its behavior when its internal state changes. The object will appear to change its class.

State pattern's diagram.

State pattern’s diagram.

At the diagram the context is the class that can have a number of internal states (in example GumballMachine). The state interface defines a common interface for all concrete states; the states all implement the same interface, so they’re interchangeable. Whenever the request() is made on the context it is delegated to the state to handle. Each concrete state provides its own implementation for a request. In this way, when the context changes state, its behavior will change as well.

The diagram of state pattern is essentially the same as strategy pattern’s diagram. However, the patterns differ in their intent. I read in the book:

(…) With the state pattern, we have a set of behaviors encapsulated in state objects; at any time the context is delegating to one of those states. Over time, the current state changes across the set of state objects to reflect the internal state of the context, so the context’s behavior changes over time as well. The client usually knows very little, if anything, about the state objects.

With strategy, the client usually specifies the strategy object that the context is composed with. Now, while the pattern provides the flexibility to change the strategy object at runtime, often there is a strategy object that is most appropriate for a context object.

(…) In general, think of the strategy pattern as a flexible alternative to subclassing; if you use inheritance to define the behavior of a class, then you’re stuck with that behavior even if you need to change it. With strategy you can change the behavior by composing with a different object.

Think of the state pattern as an alternative to putting lots of conditionals in your context; by encapsulating the behaviors within state objects, you can simply change the state object in context to change its behavior.

If it doesn’t explain the difference good enough on the next pages in the book you can read a dialogue between strategy pattern and state pattern which explains it once again and helps you remember it ;)

Other examples

Except artificial book-oriented examples on the Internet I found one nice idea/example. Actually it’s a group of posts called PHP Game Making by Bill Sanders. In the second part from the group he demonstrates usage of state pattern in, known from The Big Bang Theory, R-P-S-L-S game. Other than that there are PHP implementations for different machines with buttons ;) Searching the web I also found two interesting pages which are generally about design patterns in PHP. Maybe you’ll find them interesting:

Other design patterns

Here is the list of described by me design patterns:

Permanent link to this article: https://blog.lukaszewski.it/2013/12/29/design-patterns-state/

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>