Design Patterns Revisited: State

Design Patterns have come under mild attact lately, as seen here, and here(well, this one's not exactly recent). As a result, I decided to revisit some of the design patterns to tell truth from myth for myself.

I am going to start with the State Pattern, just because. Here we go. Straight from the Gof:

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


Back up a minute! The object will appear to change its class? Sounds like voodoo. A TCPConnection implementation is used here as an example. A TCPConnection behaves differently depending on which state it's in. So how do you encapsulate the state-specific behavior? Basically you abstract it out into a class hierarchy, which has TCPState as the abstract parent, and the specific states as the children: listening, connection established, and closed, as the the concrete state implementations. A TCPConnection object will dispatch to one of these three State strategies depending on which state it's actually in whenever it's gets an event that needs attention. In that sense, I guess TCPConnection can "appear to change its class", okay, doesn't sound that impressive after you explain it... You could always implement this by having switch statements all over the place, but this doesn't isolate all the behaviors of a state into one place - Gof mentions this in the consequences section. BTW, the consequences section is one of the best features of this book, the problem is, until you can gasp the pattern(whichever one), you probably won't understand this section. The second consequence Gof lists is that this pattern makes state transitions explicit, okay, valid, there are other ways to make this explicit(like having a state enum variable), but this is certainly one way. The third consequence is that the state object, if it has no variables, can be shared amongst any number of context objects(the holder of the states, in the example this would be TCPConnection).

Does this pattern stand on it's own? I give it a resounding yes! Does "modern" dynamic language features make this pattern unnecessary? No.

Now, with that out of the way, let's explore something a bit more exciting...

Here's an example, which was brought up by a former co-worker of mine. He had such a problem: a User could be a RemoteUser or a LocalUser, but a RemoteUser could become a LocalUser and vice versa. He wanted to know the best way to model this in the database. From his design, User would be the parent class and the other two the subclasses. I was quick to tell him to put everything in one table and use one field to specify the state of remote or local. I also thought that requiring an object to change it's type(notice that this is essentially what the State Pattern is trying to do, or to workaround not being able to do) was a ridiculous notion because the OO system just doesn't allow for that. So, clearly, changing the type of an object is something that people want to be able to do. The problem is that "remote" and "local" are really adjectives. In OO, there are only nouns and verbs. Conventionally, adjectives are represented by instance variables inside objects, in this case the variable would probably be named "state" or be a boolean named either "remote" or "local". But, the behavior of the object has to change depending on the state of this variable. The State Pattern is a way of simulating this, or to put it another way - a workaround. Workaround denotes clugginess and accidental complexity, is there any other way to do this?

Enter Mixology. This is a small ruby library from Something Nimble. It gives you the ability to unmix your mixins. Why would you want to do that? Why, it allows for a complete different way to implement the State Pattern! Just read the article in the link. I'll wait...

Basically, the way I see it, Mixology is turning the assumption of favoring composition to inheritence up side down. Well, it's not just Mixology, it's also multiple inheritence/mixins. Why? Well, why is composition more flexible than inheritence? Because 1) you can once use inheritence once(one parent) - but this problem goes away with multiple inheritence; 2) you can not change child parent relationships during runtime - Mixology fixes that. Wow! So does that mean we can start using inheritence everywhere we've been using composition? What would the world come to? Okay... I left out one reason, perhaps the most important one... 3) There's a tight coupling between the base class and the subclass, because of the implicit context in which the subclass code I plug in will be called - Erich Gamma. I can't argue with that one. But, still, inheritence has become much more powerful, with the addition of multiple inheritence and runtime switching of inheritence relationships.

Stepping back now to address the issue of design patterns being attacked. So, are design patterns bogus? I think that I have shown it's not. The example of Mixology is not meant to degrade the State Pattern but rather it serves to show that the Gof book is not the last word on design patterns and that there is room to add to and/or improve them(or worsen, if for example, switching inheritence relationships at runtime is not your cup of tea). It is much like how the Constitution was not the last word on how the government should behave.

blog comments powered by Disqus