Google analytics code

Friday, March 19, 2010

Flash / ActionScript 3: Singleton Example

Singletons are a design pattern that allows you to share one instance of a class throughout a application. An example of where a singleton is useful is when you only want one and only one connection to a database. It also allows you to keep memory usage down because there is only one copy in memory.

I've created a sample ActionScript project that shows how a singleton can be used. You can download it here.

Here is what the files look like.
Singleton_Example.as
package {
    import flash.display.Sprite;
    
    import Singleton.ExampleSingleton;
    import classes.ExampleClass;

    public class Singleton_Example extends Sprite
    {
        public function Singleton_Example()
        {
            //init the Singleton by grabbing an instance of it
            var singleton:ExampleSingleton = ExampleSingleton.instance;
            var exampleClass1:ExampleClass;
            
            
            //set the flag
            singleton.flag = ExampleSingleton.FLAG1;
            
            //show the current state of the flag
            trace("flag state: " + singleton.flag);
            
            //creating this class will update the flag in the singleton
            exampleClass1 = new ExampleClass;
            
            //the flag should be updated now
            trace("flag state: " + singleton.flag);
            
            //update the flag here
            singleton.flag = ExampleSingleton.FLAG3;
            
            //make the class display the state
            exampleClass1.displayFlagState();
        }
    }
}


ExampleSingleton.as
package Singleton
{
    public class ExampleSingleton
    {
        //a set of dummy values used to explain how a Singleton is manuplated
        public static const FLAG1:String = "value1";
        public static const FLAG2:String = "value2";
        public static const FLAG3:String = "value3";
        public static const FLAG4:String = "value4";
        
        
        //this is the only instance of the class
        private static const _instance:ExampleSingleton = new ExampleSingleton(SingletonLock);
        
        //list of allowed values that can be set for the flag
        private var _allowedValues:Array = [];
        
        //state of the flag
        private var _flag:String = "";
        
        //this will control wither the Singleton is really to be accessed
        private var _initialized:Boolean = false;
        
        /**
         * Use this to return an instance of the singleton 
         * @return 
         * 
         */
        public static function get instance() : ExampleSingleton {
            return _instance;
        }
        
        /**
         * Query the Singleton to see if it's ready to be accessed 
         * @return 
         * 
         */
        public function get initialized() : Boolean {
            return _initialized;
        }
        
        /**
         * Return the current flag 
         * @return String
         * 
         */
        public function get flag() : String {
            return _flag;
        }
        
        /**
         * Set the flag state 
         * @param value
         * @return Boolean
         * 
         */
        public function set flag(value:String) : void {
            //make sure the Singleton is initialized first
            if(!_initialized) {
                return;
            }
            
            //check to make sure it's an allowed value before setting it
            if(_allowedValues.indexOf(value) == -1) {
                return;
            }
            
            //update the flag
            _instance._flag = value;
        }
        
        /**
         * This will initialize the Singleton. It's never publicly called. Use ExampleSingleton.instance instead 
         * @param lock
         * 
         */
        public function ExampleSingleton(lock:Class) {
            if(lock != SingletonLock) {
                throw new Error("Invalid ExampleSingleton access. Use ExampleSingleton.instance");
            }
            
            initialize();
        }
        
        /**
         * This is where you would set up anything the Singleton needed before it should be accessable to the public 
         * 
         */
        private function initialize() : void {
            //we only need to initialize once. 
            if(_initialized) {
                return;
            }
            //set up what we allow the flag to be
            _allowedValues = [FLAG1, FLAG2, FLAG3, FLAG4];
            
            _initialized = true;
        }
    }
}

//this is used to lock the Singleton
class SingletonLock{}

ExampleClass.as
package classes
{
    import Singleton.ExampleSingleton;
    
    public class ExampleClass
    {
        public function ExampleClass() {
            //update the flag in the Singleton. we don't need to create a var to update it
            ExampleSingleton.instance.flag = ExampleSingleton.FLAG2;
        }
        
        /**
         * This will display the current flag from the Singleton 
         * 
         */
        public function displayFlagState() : void {
            trace("flag state from ExampleClass: " + ExampleSingleton.instance.flag);
        }
    }
}

Lets start with ExampleSinglton.as. The important parts of this class are the _instance member variable, the instance getter method and the ExampleSingleton constructor.

The constructor takes a SingletonLock class argument as a locking precaution. This class is defined at the bottom of the ExampleSingleton package. This allows us to control the way the class is created. The _instance member variable is where we create the instance of the ExampleSingleton. The ExampleSingleton constructor should check to make sure the lock argument is a SingletonLock class and throw an error if it isn't. The error you throw should let the person know how to properly access the singleton.

ExampleSingleton.initialize is where some basic values are set up that are accessed in the rest of the project.

Now lets look at Singleton_Example.as. When we create the singleton variable we access the .instance property of the class. This will return the single instance of ExampleSingleton.

ExampleClass.as also uses the ExampleSingleton class. You'll see how setting a property on ExampleSingleton in Singleton_Example is reflected in ExampleClass and vice versa.

No comments:

Post a Comment

If you found this page useful, or you have any feedback, please leave a comment.