<a href="http://www.micropoll.com/akira/mpview/585320-168921">Click Here for Poll</a><a href="http://www.questionpro.com" title="online surveys">Online Survey</a><BR> | <a href="http://www.micropoll.com" title="Website Polls">Website Polls</a><BR> | <BR><a href="http://www.micropoll.com/akira/MicroPoll?mode=html&id=168921">View MicroPoll</A></div>

Visual Studio 2010!

Read now >

Windows Mobile Development Thoughts

Read now >

View Now
DevSource RSS FEEDS
XML Want an easy way to keep up with breaking tech news? And the Get DevSource headlines delivered to your desktop with RSS.
ADVERTISEMENT
ADVERTISEMENT

 

ADVERTISEMENT
Imitation is the Highest Form
By Paul Kimmel

Rate This Article: Add This Article To:

Elevate your programming to an art form. Learn how to implement a no-nonsense behavioral pattern, the state pattern, by (how often do we get to say this?) following the bouncing ball. State patterns let you separating the behavior of objects via

In any endeavor, speed comes with practice. By practicing, we form habits. But the question is: what do we practice? People like Martin Fowler, John Opdike, and Erich Gamma have answered this question for us. We practice implementing patterns and refactoring, and we avoid anti-patterns.

Refactoring, a process of simplifying code in an almost algebraic way, is guided by rules and leads to a predictable result. Patterns are known, general solutions to recurring problems. Anti-patterns are (you might have guessed this:) the opposite of patterns.

Each of these things—refactoring, patterns, and anti-tatterns—are evolving ideas. Refactoring and patterns are too complicated to master all at once. However, we can master useful facets, one at a time, accumulating a toolbox that will help elevate your programming effort into art. In this article, I will demonstrate how to use the State pattern.

What is the State Pattern?

The State Pattern is classified as a behavior pattern because it addresses a class of problem that has to do with the behavior of classes. Generally, the state pattern permits you to sub-divide the internal behavior of an object based on that object's current state. Perhaps more directly, the state pattern replaces flags with internal classes.

Consider a simple business object. In edit mode, you may want to show some controls and permit some inputs; in browse mode, you may not want to permit edits. Historically, you might track the current mode and use conditional logic to determine what is enabled, what is visible, and what kinds of validation (if any) need to be performed. The result may be a single method with two, three, or more blocks of code; only one block executes, based on a flag-state. Often, this can result in spaghetti code as you try to manage behaviors that intersect across states. The more complex the class and the greater the number of flags, the more tangled the spaghetti becomes.

The state pattern untangles spaghetti code by solving only one aspect of the object's state-dependent behavior at a time.

I will keep the demonstration brief, but I want you to realize that the State Pattern yields the greatest results for very complex problems. Trivial problems (like my example) can be coded successfully in almost any manner.

Think of a bouncing ball. When you drop the ball, gravity pulls it downward. Then the force with which it hits a hard surface, the weight of the ball, and the elasticity of the ball determine how high the ball bounces upward. Finally, left unattended, the ball's bounce deteriorates gradually and the ball settles on the surface. Generally, the ball does two things: it moves downward and upward.

Note: Every child can bounce a simple ball. This is perhaps one of the first games children everywhere learn. It is interesting to point out how much effort it takes for a computer program to perform the same task in the digital world. If we were to expand our simple Ball code into all of its supporting code it would be millions of lines of code. This illustrates what is often overlooked by myopic non-practitioners: programming is labor intensive and difficult to do well, and it takes time.

To capture the behavior of a ball in code, we need to know in which direction the ball is moving. Depending on the necessity of the solution domain, we may need to know other factors. To avoid stressing my mathematics too greatly, we will focus on down and up.

Implementing the Ball Class

I actually became quite distracted with playing with simple movements of the ball and state pattern, making the ball bounce, zig-zag, roll, and follow basic shapes like a square. However, we will stick to a basic ball behavior, calling it Move. Listing 1 shows a basic implementation of the Ball class, first demonstrating a flag to guide the ball's motion up and down.

Listing 1: A Ball class using plain a flag in the form of an enumerated type, Direction.

using System;
using System.Drawing;
using System.Windows.Forms;

namespace StatePattern
{
  public enum Direction{  Up = -5, Down = 5 };

  public class Ball
  {
    private Control control = null;
    private Rectangle bounds = Rectangle.Empty;
    private Direction currentDirection = Direction.Down;
    private Timer timer = null;

    public Ball(Control ball)
    {
      control = ball;
      bounds = ball.Parent.DisplayRectangle;
      timer = new Timer();
      timer.Interval = 50;
      timer.Tick += new EventHandler(OnTick);
    }

    public void StartMoving()
    {
      timer.Enabled = true;
    }

    public void StopMoving()
    {
      timer.Enabled = false;
    }

    public int X
    {
      get{ return control.Location.X; }
    }

    public int Y
    {
      get{ return control.Location.Y; }
    }

    public Rectangle Bounds
    {
      get{ return bounds; }
      set{ bounds = value; }
    }

    public void Move(int x, int y )
    {
      control.Location = new Point(x, y);
    }

    public void Move()
    {
      if( !CanChangeLocationTo( new Point(X, Y + (int)currentDirection)) )
        ChangeDirection();
      Move( X, Y + (int)currentDirection );
    }

    private void ChangeDirection()
    {
      currentDirection = (Direction)((int)currentDirection * -1);
    }

    private void OnTick(object sender, EventArgs e)
    {
      Move();
    }

    internal bool CanChangeLocationTo(Point newPoint)
    {
      return newPoint.X > 0 && newPoint.X + control.Width < bounds.Right
        && newPoint.Y > 0 && newPoint.Y + control.Height < bounds.Height;
    }
  }
}

The first implementation of the Ball class uses an initialized value for the enumerated fields Down and Up. These positive and negative values, respectively, are used to position the ball. This code is a bit clever—in the poor sense of the word—because using the enumerated type to position the ball clouds up the code (more so than would a simple if-condition test on the direction). Additionally, as simple as this code is, we are already managing the state of the Direction enumerated field currentDirection. In commercial software, the number and variety of flags can be huge and diverse, resulting in very complex conditional logic.

Figure 1: A form used to visualize the movement of the ball.

Bouncing the Ball Using the State Behavior Pattern

Now, let's see how we might bounce the ball using the state behavior pattern. The process entails isolating the behaviors, and separating divergent behaviors into behavior classes. Finally, we revise our original class to implement its behaviors in terms of the state class.

Following the basic instructions, we know that we have a downward moving state and an upward moving state. The basic behavior is Move for both down and up. It is how we implement the polymorphic Move that defines the realized behavior. Factoring out Move as a state behavior, we can define a base class with an abstract method Move. Add a reference to the abstract base class, and generalize the abstract State class Move as MoveDown and MoveUp. We wrap up by implementing the Ball's Move behavior in terms of the Move class' behavior and change the instance of the concrete move classed based on direction. Listing 2 shows my implementation.

Listing 2: Implementing movement as State Behavior.

using System;
using System.Drawing;
using System.Windows.Forms;

namespace StatePattern
{
  public enum Direction{ Down, Up };

  public class Ball2
  {
    private Control control = null;
    private Rectangle bounds = Rectangle.Empty;
    private Direction currentDirection = Direction.Down;
    private Timer timer = null;
    private MoveState state = null; 

    public Ball2(Control ball)
    {
      control = ball;
      bounds = ball.Parent.DisplayRectangle;
      state = new MoveDownState(this);
      timer = new Timer();
      timer.Interval = 50;
      timer.Tick += new EventHandler(OnTick);
    }

    public void StartMoving()
    {
      timer.Enabled = true;
    }

    public void StopMoving()
    {
      timer.Enabled = false;
    }

    public int X
    {
      get{ return control.Location.X; }
    }

    public int Y
    {
      get{ return control.Location.Y; }
    }

    public Rectangle Bounds
    {
      get{ return bounds; }
      set{ bounds = value; }
    }

    public void Move(int x, int y )
    {
      control.Location = new Point(x, y);
    }

    public void Move()
    {
      if( !CanChangeLocationTo( new Point(X, Y + (int)currentDirection)) )
        ChangeDirection();

      state.DoAction();
    }

    private void ChangeDirection()
    {
      if( state.MyDirection == Direction.Down )
        state = new MoveUpState(this);
      else
        state = new MoveDownState(this);
    }

    private void OnTick(object sender, EventArgs e)
    {
      Move();
    }

    internal bool CanChangeLocationTo(Point newPoint)
    {
      return newPoint.X > 0 && newPoint.X + control.Width < bounds.Right
        && newPoint.Y > 0 && newPoint.Y + control.Height < bounds.Height;
    }
  }

  internal abstract class MoveState
  {
    public abstract Direction MyDirection{ get; }
    protected Ball2 ball = null;

    public MoveState(Ball2 ball)
    {
      this.ball = ball;
    }
    
    public abstract void DoAction();
  }

  internal class MoveDownState : MoveState
  {

    public MoveDownState(Ball2 ball) : base(ball){}

    public override void DoAction()
    {
      ball.Move(ball.X, ball.Y + 5);      
    }

    public override Direction MyDirection{ get{ return Direction.Down; } }

  }
  
  internal class MoveUpState : MoveState
  {
    public MoveUpState(Ball2 ball) : base(ball){}

    public override void DoAction()
    {
      ball.Move(ball.X, ball.Y - 5);
    }

    public override Direction MyDirection{ get{ return Direction.Up; } }
  }

}

The revisions include an abstract base class called MoveState and two child classes—MoveDownState and MoveUpState—that generalize the abstract behavior as downward and upward movement. The Ball class contains a MoveState field. When the ball needs to change direction, we change the instance of MoveState to MoveDownState or MoveUpState as the case may be.

As you can see from the listing, the code has actually grown in size. Patterns may not initially reduce the amount of code you have to write; rather, they act as solutions known to work. In the case of the State Pattern what we have accomplished is a simplification of the interactions by reducing the dependency on conditional logic and flags.

For very simple problems, hacking out any old solution will probably work. For classes with just a couple of flags, perhaps the state pattern is still overkill. However, for complex classes with a lot of states, this pattern can be a life saver.

Another benefit of using the state pattern is that it becomes very easy to sub-divide or even outsource work. Consider the MoveState class itself. The abstract class indicates clearly what the public interface is, permitting independent developers to work on tidy class sub-divisions of the same problem.

Patterns are known general solutions to kinds of problems. The State Pattern is a behavior pattern that makes it easy to sub-divide internal behavior by implementing separate classes for all of the possible state's behaviors. The problem is then decomposed into making each state work correctly, independent of any other state. Your focus is one problem at a time.

Now, In The Real World...

Each time I write one of these articles, I reflect on a real, antagonistic dichotomy in software development. That is, management and customers don't seem to care how the code is crafted. The only reward for knowing about and using patterns (or anti-patterns and refactoring) is the pleasure in doing the thing itself. Rationally, we believe that our chances of succeeding improve with technique, that cost of ownership should be lower, and our peers may be a little impressed. But if someone else seems to solve the outward problem faster, then technique won't impress anyone.

Sadly, most managers, all customers, and even many programmers work on projects whose schedules are dictated. There is real downward pressure on the costs of the here and now. This myopic view leads to leaving time for testing on the cutting room floor, and a complete indifference to qualitative aspects of software development that impact reliability, cost of ownership, and long term customer satisfaction.

In short, don't say I didn't warn you. If you miss a deadline your boss won't care that it was because you were writing quality code but it took longer. This doesn't mean you should not use patterns; just implement them very quickly.

Paul Kimmel is the founder and chief architect for Software Conceptions, Inc. and a co-founder and President of the Greater Lansing Area .NET Users Group. He has written several books on .NET and object oriented programming and is available to build software for your company.




Discuss Imitation is the Highest Form
 
>>> Be the FIRST to comment on this article!
 

 
 
>>> More ASP and .Net Coding Techniques Articles          >>> More By Paul Kimmel