Lecture thumbnail 0:00 / 0:00 If you actually go ahead and you check out the state design pattern as it’s implemented in the Gang

of four book, which I remind you was written in 1994.

Well, if you check out their examples, you’d realize that something is seriously wrong, that the

examples in the Gang of Four book are not really the way that we do state machines today.

So even though I didn’t really want to show any kind of example which leverages state machines in the

same way as they did all those years ago, I thought I would cover it as a kind of academic exercise

because the implementation that you’re about to see is not the kind of implementation I would recommend.

I would say that it’s not just a case of overengineering, but a case of bad design.

But let’s actually talk about it.

What we’re going to be modeling is a very simple light switch.

Now, a light switch has two states.

Either the light is off or the light is on.

But the way that the classic implementation of the state design pattern handles the light switch or

indeed a similar construct is a bit bizarre.

So we’re going to take a look at how we can implement this.

So first of all, we’re going to have a class for a switch.

So a switch is going to have a bunch of methods for switching the light on and switching the light off.

But the interaction with the state is going to be very specific because in the classic implementation

of the state design pattern, each state is a class.

It’s not just an enum member of some numeric constant.

It’s actually a heavyweight class, not something that I would recommend doing ever.

Even if you’re in a situation where your states have to have lots of special behaviors, this is not

where you put them.

But let me show you how this can be.

This can be implemented.

So typically what you would do is you would have some sort of base class, maybe some abstract base

class called state.

And this class would have virtual methods for performing the operations, which kind of transition you

from one state to another.

So you would have, let’s say, a virtual method for turning the light on.

And similarly, you would have a virtual method for turning the light off.

Okay, So these two methods are going to somehow switch the lights, but in actual fact, the implementation

of both on and off is also very weird.

I don’t even want to fill it in right now because you’re going to find everything to be a bit confusing.

So what we’re going to do is we’re going to inherit from this abstract state class and we’re going to

define our two states.

So we have the on state when the light is on and we have the off state when the light is off.

So let’s have a class called on state.

So this is going to inherit from state and we’ll have a constructor.

We’ll have a constructor.

Now in the constructor, the assumption is that when you call the constructor, when you create the

on state you are.

Let’s say you’re kind of entering that state and therefore by the time you are at this particular point

in code, the light gets turned on.

So that’s what we’re going to write here.

Light turned on.

Okay, So this is probably the end of the kind of obvious stuff related to the classic implementation

of the pattern, because now we’re going to see complications.

Now we’re going to see a kind of bidirectional relationship between the switch, which is our control

element, which allows us to switch from one state to another.

And the actual states, which also, bizarrely enough, have their own on and off methods.

So let me let me show you how this can work.

So inside the switch, inside the switch class, we’re actually going to have a variable.

It can be a field or a public property which is going to store an instance of the current state.

So public state, state equals.

And we start with the off state, by the way, and I haven’t constructed the off state.

So let me just do it quickly here.

So we’ll have an off state which is also going to inherit from state.

And let me define the constructor similarly to the way we’ve done here.

So here I’m going to say light turned off.

Okay.

So coming back down here, what we know is that the switch starts in the off state.

You’ll notice that there is a bit of polymorphism here.

So the off state inherits from state.

So the type of variable here is state.

And as you may have guessed, at some point the state variable gets replaced.

So we replace it with an on state.

If we switch the light on and then our light switch has the on and off methods, so we’ll have public

void on and public void off.

Now what happens in the classic implementation of the state design pattern is that you tell the state

to switch itself from one state to another.

And what I just said is it sounds stupid and it actually is stupid.

But let me let me show you how this can work anyway.

So we take the current state.

Now, remember, this is a polymorphic call because the state class is abstract.

So these are virtual members.

You might be calling them in the on state.

You might be calling them in the off state.

You don’t really know.

So you say state dot on and you pass the switch.

So once again, if you are experienced in object oriented design, this might be a code smell for you.

Like why are we passing the control element into the state which then mutates the control element back?

It’s a kind of bidirectional thing.

And here you would do state dot off once again passing this.

Okay, So as you can see, there are parameters here and we need to add them.

So here in the base abstract class, we pass the switch switch as W here and switch as W here.

Now what happens inside the default implementation is because remember, this is a base class.

What happens inside the default implementations is even more weird because what we’re going to do here

is we’re going to say that light is already on.

And similarly here we say that light is already off.

So it’s probably hard for you to understand why exactly we are doing this.

You’ll only see everything once we get the full picture and the full picture.

We’re going to get in just a moment, because for the on state, it doesn’t make any sense for the on

state to switch itself on because it’s already on.

So the only thing you would implement here is you would override the off method, override the off method.

And this is where you can say, for example, that we are turning the light off and we can actually

turn the light off.

Now, the way this is done is by taking the switch that got passed in as W taking its state property

or field and setting it to a new off state.

And we can now do a symmetric operation inside the off state.

So here we would override the on method.

Here we would say turning light on and we would say that as W dot state equals on state, a new on state

like so.

All right.

So this is our setup.

And if you are confused by the setup, that’s no problem.

It completely makes sense for you to be confused by this because it’s far from intuitive.

But let me finish off the demo, first of all.

So we make a light switch, var LHS equals new switch.

We can turn the light on, we can turn the light off and we can turn the light off again.

So the light is already off, but we’re allowed to turn it off once again.

Okay, so how would this work?

Let’s try tracing our steps as we call something.

So we take a light switch and we call the on method on it.

So we call the on method on this whole thing and let’s see where we end up.

So we end up in the on method here.

What we do is we take the current state as it is and we tell the current state that we want to perform

a transition from whatever state we are in can be virtually anything to the on state.

So following this, we end up in the abstract base class on and of course this would have some implementation.

So if we’re starting out with the off state, then on will be called in the off state.

So we come back here, everything is okay.

We the light was off, we are turning the light on.

And then what we do is we take the switch, which is kind of like a user interface effectively.

So the switch here is the user interface.

We take the user interface and we modify its state, but we don’t modify it in the sense of just changing

a numeric value or a Boolean value, which is what you would expect in this particular case.

You would expect a Boolean to indicate whether the light was on or off and you would say, s w dot on

equals true, something like that.

But here what happens is we substitute a state object, we replace it completely with a new object of

type on state.

And then of course, when we call off here, the opposite operation happens.

So we call off here, which does state dot off.

Remember, the state is now an on state.

So we end up here in the off and we turn the light off.

So this operation does work.

And now we come to calling off again.

This is the interesting case.

This is the unique case of this example because when we call off, the light is already off.

We are already in the off state.

So when we call state dot off and the state is off state, you’ll notice that off state doesn’t have

enough method.

It doesn’t have an off override, it has an own override, which is not our case.

So where would it find the off method?

It would find it right here.

And that explains why in the.

A base class in the base class right here.

Rather why you would actually have the on method telling you that the light is already on and the off

method telling you the light is already off.

Because if you are in here or if you’re in here, you’re trying to repeat the state that you’re already

in.

You are cycling the state, you’re not moving to a different state.

You’re trying to get into the same state once again, which is why we don’t do the overrides when so

these methods actually get called.

Now let’s run the entire example.

Let’s just run it and let’s see what we get.

Okay.

So as you can see, initially light turned off.

Then we are turning the light on and the light is turned on.

We’re turning the light off, the light is turned off and then we are trying to turn the light off again.

But the light is already off.

So that is our scenario.

So I’m including the scenario here for completeness.

This is not the way that we build state machines nowadays.

And in actual fact, if you didn’t know, if you didn’t do any analysis on this entire demo, you wouldn’t

know what’s going on here because the whole implementation is very unintuitive.

First of all, it’s wasteful.

You don’t really need to have every state modeled by a class unless you really want to, unless there

is a lot of logic that has to go into the state.

But typically the logic goes not into the states, but into the transitions between the different states.

Now, unfortunately, what happens here is the transitions themselves are handled inside the states

themselves.

So when you flick on a switch, this does nothing but call the appropriate method on the state, which

from just a purely perceptive perception of perspective, doesn’t make any sense.

Because when I when I have a particular state of an object, I don’t invoke behavior on that state.

I invoke behaviors outside.

Maybe I take my hand and I press the switch.

So that is my behavior.

That is the behavior of the switch.

It’s not the behavior of the actual state.

So this entire demo is basically just a historic and academic demo that certainly it does work, it

does function, and there’s even trickery with the virtual method so that if you are cycling a state,

if you’re already in a particular state and you end up in that same state again, you have some specific

outputs here in the abstract base class.

But apart from that, this is not the kind of code that I would recommend.

And we’re going to take a look at much better implementations of state machines.

Play Stop Play Play Play Play Start Play information alert