Simple State Example


Our first attempt at representing the basketball shooter and its various states is very simple. In fact, you've probably built classes just like this before. This shooter class meets all the criteria of the State pattern but is a naive and inelegant solution that presents further problems. We'll look at this example first to understand how we can later improve on this.

Create the Simple Shooter Class

The SimpleShooter class holds all the shooter functionality for each state. The state is set in the setState() method. This method takes a stateName as the parameter. The value of this parameter is saved in a class property called stateName.

There are three constants defined in this class that represent the three state names: LAY_UP_STATE, FREE_THROW_STATE, and ThrEE_POINTER_STATE. They should be used when calling the setState() method to ensure accuracy.

The SimpleShooter class also has a getAccuracy() method to determine the percentage of shots made from that state. And there is a getPointValue() method that returns the point value of a made shot from that state. Each of these methods has a switch statement that determines the state in which the object is.

package com.peachpit.aas3wdp.stateexample {    public class SimpleShooter {       private var stateName:String;       public static const LAY_UP_STATE:String = "lay_up_state";       public static const FREE_THROW_STATE:String = "free_throw_state";       public static const THREE_POINTER_STATE:String = "three_pointer_state";       public function SimpleShooter() {}       // Returns the shot accuracy percent of the current state       public function getAccuracy():Number {          switch(stateName) {            case LAY_UP_STATE:               return 0.9;            case FREE_THROW_STATE:               return 0.7;            case THREE_POINTER_STATE:               return 0.4;            default:               return 0;          }       }       // Returns the made shot point value of the current state       public function getPointValue():Number {          switch(stateName) {            case LAY_UP_STATE:               return 2;            case FREE_THROW_STATE:               return 1;            case THREE_POINTER_STATE:               return 3;            default:               return 0;          }       }       // Sets the current state of the object          public function setState(stateName:String):void {             this.stateName = stateName;          }       } }


Create the Main Example Class

We'll build a class called SimpleShooterExample, which serves as the starting point for this example. This class creates the shooter object, sets the state, initiates ten shots at a constant time interval, calculates the outcome (whether or not the ball went through the hoop) based on the accuracy property, and keeps track of the points. After each shot, we output the outcome of the shot. The outcome of the shot and the point value are determined by the internal state of the shooter object. The following is the code for our implementation class:

package {    import flash.display.Sprite;    import flash.utils.Timer;    import flash.events.TimerEvent;    import com.peachpit.aas3wdp.stateexample.SimpleShooter;    public class SimpleShooterExample extends Sprite {      private var _points:Number;      private var _shooter:SimpleShooter;      public function SimpleShooterExample() {         // Initially set the points to zero         _points = 0;         // Create the SimpleShooter instance and set its state         _shooter = new SimpleShooter();         _shooter.setState(SimpleShooter.THREE_POINTER_STATE);         var shotInterval:Timer = new Timer(1000, 10);         shotInterval.addEventListener(TimerEvent.TIMER, onShot);         shotInterval.start();      }      private function calculateShot(accuracy:Number):Boolean {         return Math.random() < accuracy;      }      private function onShot(event:TimerEvent):void {         if(calculateShot(_shooter.getAccuracy())) {            _points += _shooter.getPointValue();            trace("Made the Shot!  " + _points + " point(s)");         }else {            trace("Missed the Shot!")         }      }   } }


The SimpleShooterExample class has two properties: points and shooter. The points property holds the running total of our points across all ten shots; the shooter property holds the instance of the SimpleShooter object. Inside the constructor, we create that SimpleShooter object and set the state of it.

The shot is calculated by grabbing the accuracy of the current shot. This is a percentage at which shots from that state are typically made. We run that though a simple probability function called calculateShot(). If the accuracy is 80%, the calculateShot() method returns true 80% of the times it is called and false for the remaining 20%.

Problems with This Example

Although the example we just described works and is simple to understand, there are a couple major problems with it.

The first problem is scalability. This solution simply will not scale well. Consider an option with 100 states and 20 methods per state. The resulting class would be huge. And each time you add or remove a state, you'd have to modify every method.

This transitions us nicely to our second problem: maintainability. If we have to modify massive amounts of code for each change request, we're opening ourselves up to having a lot of bugs. To prevent this from happening, we should encapsulate each of the states in its own class and close those states for modification. This makes the application easier to perform Quality Assurance (QA) testing and debugging.




Advanced ActionScript 3 with Design Patterns
Advanced ActionScript 3 with Design Patterns
ISBN: 0321426568
EAN: 2147483647
Year: 2004
Pages: 132

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net