The state behavioral pattern allows you to simplify your code when you have different modes of operation.
This is really just a specific application of polymorphism. You have a class that needs to performs some action in one of several different ways. Instead of writing all the code to perform the action in each mode, you instead define an interface with all the actions and have your class call through an instance of the interface.
You then declare separate concrete classes that implement the actions in their own way or in their own mode. With these concrete classes, you just need to select one and update the class that wanted to perform the action in the first place to refer to one of the concrete implementations.
The episode describes a command class that implements the ability to move a hero in an adventure game forward. When the hero could only walk, maybe it makes sense for the command to directly implement the code needed to move the hero forward. But when another mode of transport is introduced such as riding a horse, the command class would have to choose between the two different ways of moving forward. This pattern describes how to have the command class call a virtual moveForward method instead. This method will resolve to either walking or riding.
The nice thing about this pattern is that it makes it easy to add more modes. We could add swimming or rowing a boat as additional modes of transport for the hero. In each of these cases, the command to move forward doesn’t have to change or be extended anymore. It just calls the move forward virtual method of the state object. Listen for more about this pattern or read the full transcript below.
The basic description says that this pattern allows objects to alter their behavior when internal state changes and this causes them to appear to change classes.
Many applications and games have different modes where it seems like everything changes. A drawing program will have a set of tools that change the meaning of clicking and dragging with the mouse. One tool might select and then move images while another tool might outline and then resize images. Some games might allow the hero to move around and interact with the world differently when on foot vs. when riding a horse.
These are the types of modes this design pattern helps you to simplify. To see how, let’s first think about what your code might look like without this pattern.
Now this is going to be a short episode because this pattern is so heavily focused on the structure of the code. I can’t effectively read code on the podcast and have any chance that you’d understand. This is the biggest reason I stay away from reading actual code. That’s what the live classes are for. But I’ll do my best to describe in general terms how this pattern can help you write better code.
Imagine you’ve already implemented the command design pattern from episode 72 and you’re about to execute a move forward command. Walking and riding a horse are very different activities but both can support the idea of moving forward. Without this state pattern your code might have an if statement that says “if walking” then move forward like this block of code describes, “else” then move forward like this other block of code describes.
The total length of the code in the command source file will be longer because it has to accommodate different ways of moving forward. This pattern will be repeated for every other command too.
What happens when you need to add support for swimming? Now you need to go through all the commands and not only add the extra code but change the structure of your if statements. Maybe you decide to toss the if statements and go with switch statements instead.
A switch statement is just a different way of writing a long series of if, else if, else statements.
I’ll show you how you can use this pattern to simplify things a bit right after this message from our sponsor.
( Message from Sponsor )
Okay, so we have walking, riding, and now swimming to deal with. And let’s plan on a few others even if we don’t know what they’ll be yet. Usually when writing code, one type of behavior is not enough to highlight common parts unless you’ve got some experience already. Two types should raise some alarms and start the refactoring. And three is almost a sure sign that more will be coming.
The command pattern showed us how to turn a command into an object that can be saved and executed later and how it can originate from different sources. Once we’re in the execute method, we know that we need to actually move forward now. Or do whatever else the command needs.
Here’s where the state pattern helps. Instead of jumping right into an if statement or a switch statement with the code for accomplishing the command, we need to go through another level of indirection.
First start by creating an interface that describes all the possible actions supported by the various modes. In this example, there’s things like moveForward, moveBackward, etc. But there might also be actions like enter and leave. We could use these to show the hero mounting and dismounting a horse or picking up and releasing oars for a rowboat mode. See, I told you there’d be more modes.
And some actions might only apply in certain modes. That’s okay. Jumping doesn’t make sense when swimming but it does when walking or riding a horse.
Then you can define concrete classes to implement these actions. This has a nice benefit of putting related code back together. The moveForward command was starting to collect quite a diverse set of behavior that it had to choose from. This gets all the walking code whether it be walking forward or backward into a walkingMode class. It actually makes it easier to understand already.
But it gets easier. Because the hero can only be in one mode at any time, you might find the singleton pattern helps you with your design. The singleton is described in episode 60. Somewhere, you just need to put a reference to the interface that describes all the actions available to all modes and make sure this reference points to the current concrete mode class.
The moveForward command code can then skip all the if/else or skip the giant switch statement and just call the moveForward method in the current mode.
When you want to switch modes or switch states, just update the current mode reference to point to a different mode.
And when you want to add a new mode, you no longer have to edit all of your commands to add another case statement to the ever increasing switch statement. Just swap out the current mode with the new one at the appropriate time.
Now, this pattern doesn’t describe how to switch the current mode. That’s up to you. This pattern just helps make sure that you have a current mode to work with.
In addition to when you want to switch states, you also need to decide what to do with the old state. Do you delete it? Do you keep it and all the others in a master collection somewhere? If your application switches states rapidly and the mode classes are expensive to create, then you might want to keep them around and reuse them. It’s really up to you.