State Pattern — What It Is And How To Use It?

Bhuvnesh Maheshwari
The Startup
Published in
5 min readFeb 15, 2021

--

The Super Mario Game

If you were born in the 1990s then the above picture needs no introduction. It will surely make you go back to those nostalgic memories where the Super Mario game was the only thing to do on summer vacations 😆. The surprising fact of the game is the original file size of the game was a mere 32 KB, less than a modern-day picture! We will learn the state design pattern by implementing a small yet important piece of a Super Mario game. Let’s take a look at what we want to implement.

Requirements

We want to implement the behavior of a player in the Super Mario game. For example,

  1. Child State — Initially, the player will be in a child state when the game starts. In a child state, the player has certain restrictions like slow running speed, smaller length of the jump, can not break the wall, upon encountering the obstacle the player will die.
  2. Adult State —In this state, the player will have more power compared to the child state. He will be able to run faster, jump to greater length, break the wall. Also, the player’s state will be changed to a child state if he touches the enemy.
  3. Army State — It is the most powerful state of the game. Apart from the basic power of the player, it can shoot the enemy on the ground from distance. However, if the player encounters the enemy then it will be moved back to the adult state.

How can we design and implement the above requirement such that our code is maintainable and easy to accommodate new requirements in the future?

Let’s think naively. The Player class can be implemented as follows. We can represent our states as constant integers. When the client instantiates the object of a player, it will create an instance with the child state. After that, as the game progresses we can call the methods like jump(), shoot(), run(), etc. Based on the current state of the player, it will update perform the operations. So far so good!

However, there are problems with this approach! Can you guess? Here are some of them,

  1. Open Closed Principle ❌ Open Closed principle is clearly violated in the above design. If we want to add a new behavior or introduce a new state of the player then, we will be forced to modify each of the methods defined in the player class. Not only new state will be hard to implement but all our unit tests will need to be modified.
  2. Further modification can introduce bugs in the existing working functionality of the game.
  3. Take a look at jump(), run(), and encounteredEnemy(), upgradeState() methods. We are relying on a bunch of if..else.. blocks, which is bad. Currently, the use case is simple but in the real world, the state transition could be much more complex.

Now, let’s look at how the state pattern can solve this problem!

We have a player class that is the main character of our game. It has other responsibilities apart from its current state. Additionally, we can observe that the state of the player changes throughout the game. Based on the state, the behavior of a player will be determined at run time by the game engine. So why not separate that changes from what remains the same!

Step 1 — Define the State Interface

It contains methods for every action of a player. All our concrete states will implement this interface. One of the benefits of having an interface is that now every state has to abide by the contract of the interface — to implement all the methods declared in the interface! This will certainly throw a compile-time error if a programmer forgets to define one of the methods in the concrete implementation, which is a good thing 😃.

Step 2 — Define Concrete States

Let’s define each individual state that a player can be transitioned. For our case, we’ll have a child state, an adult state, and an army state. These states will have a reference to the player object. Using it, we can change the state of a player. Code simplicity and readability can be noticed here as compared to the naive solution that we implemented above.

Step 3 — Delegate the responsibility to the State class

This is pretty simple. We just need to define setState() and updatePosition() methods in the player class. It will also contain a reference to the state object.

Using this reference the game engine can alter the state of the player throughout the game. When client calls the encounteredEnemy() method it is delegated to the current state. For instance if current state is AdultState then, encounteredEnemy() method defined in the AdultState will be executed at runtime. And it changes the current state to ChildState, which is what we want!

Recap of what we did! 😃

  1. Removed if-else repetitive conditions from each method. Using the state pattern, we localized the method behaviors to their respective concrete classes. This makes more sense as these behaviors belong to a given state of a player. So instead of putting all these behaviors in a player class, we modularised our code and put it into its respective states.
  2. The state pattern has enforced us to follow the open-closed principle ✅. I don’t need to elaborate on this! Adding a new state to the application is pretty straightforward. Just create a class that implements the state interface and implement the behaviors of the new state! At the same time, we don’t need to touch our existing states while implementing the new state.
  3. The code is easy to read, easy to maintain, and much more logical.

What is the state pattern?

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

Okay, but wait don’t you think we are using the same principles of Strategy pattern? Let’s look at the differences between the two.

State Pattern Vs Strategy Pattern

The main difference lies in the intent of use of both the patterns.

We use the state pattern as an alternative to putting lots of if..else..in our context; by encapsulating the behaviors withing the state objects, we can simply change the state object in context to change its behavior.

While strategy pattern is an flexible alternative to subclassing. If we use inheritance to define the behavior of a class, then we are stuck with that behavior even if we don’t need it. We should not expose methods or behaviors to classes which does not need it. With the strategy pattern we can change the behavior by composing with a different object.

Phew! That is it! We have learned the state design pattern! I think it was one of the cool pattern. Hope you felt the same 😃

See you in the next pattern! Till then bye 👋.

--

--

Bhuvnesh Maheshwari
The Startup

Let’s be an awesome developer together! I will be learning the tech and sharing it with the community.