The Extendable Singleton Pattern
June 5th, 2008 Posted in ActionScript, Flex Development, Rich Internet ApplicationsThe Singleton pattern is one of my favorite little patterns that can be used in any language that provides static typed properties/methods. There are many different uses of the Singleton and just as many ways to implement them within code. In this post I am going to first introduce the basic Singleton pattern, explore how it is most often defined in ActionScript (including tips on protecting the Singleton instance), then talk about how to create an extendable Singleton and why on earth you would want to. If you already know the principles of Singletons, skip ahead to the second section of this post “Defining Singletons in ActionScript”.
What Is a Singleton?
If you have never heard of the Singleton Pattern you are not alone, I know many senior Java and ActionScript developers that looked at me blankly when I brought up the pattern in passing. The core idea of the pattern is to solve the issue of when you need only once instance of an object that can be accessed globally in you application.
For example, you have a User object that stores the user information once they are logged in. Throughout your code you want to use this information and you also want to make sure that there is only once instance of this user data. One solution is to pass around a value that represents the user, yet there are many issues with this kind of approach. First, the code needs to understand this data and expect it when called. Second, what happens if the user logs out or changes the data, such as their address? The code needs to know this the next time its called. Passing it around gets ugly very very fast.
Another solution is to save the values in a global variable. But where should this live and how should it be accessed? Does it live in _root (really, really bad idea) or the top Application? What happens when your code gets nested in another application or is modularized? How can you find the data? This is where the singleton comes in. The Singleton pattern leverages the power of static properties and methods which are bound to the Class type itself. What!?! Let me show you:
package com.vivisectingmedia.example { public class User { public var name:String; public var address:String; public var birthDate:Date; } }
So there is our basic user class. Its just a simple data object class that stores our information. In most cases we create a new instance of it and then start manipulating it, such as:
var loggedInUser:User = new User(); loggedInUser.name = "Bob"; loggedInUser.address = "123 Market St."; loggedInUser.birthData = new Date(1976, 4, 6);
In the above example we are working with an instance of a class. We used the constructor to generate the instance and we are manipulating the properties of that instance. In ActionScript 3.0 we can leverage the static keyword to define properties on the class itself:
package com.vivisectingmedia.example { public class User { static public var name:String; static public var address:String; static public var birthDate:Date; } } .... // we now access the name value through the Class, not an instance User.name = "Bob"; User.address = "123 Fake St."; User.birthData = new Date(1976, 4, 6);
Those values are being set on the Class not on an instance. This means that when you change values in one part of the code and then access the class in other parts of the code the stored values are the same. In a way we have just defined a global data object that stores our user data. The Singleton pattern takes the ability to store values on the Class and then steps it up a notch.
In theory we could go in and mark EVERYTHING static but this is not ideal and can lead to complications. The better way is to create a hybrid of the first User class example and the second. We do this by exposing a static method on User that checks if an instance of User is created and if not creates one and then returns it. This part of the Singleton is kind of a mind-bender so lets just jump into code.
Defining Singletons in ActionScript
The core idea of the Singleton is to have static helper methods that manages our object instance by allowing only one instance to exist and also provides access to this instance. Using the User example (above) here is a complete Singleton which also follows the extendable pattern. Don’t worry if you don’t get all of it on the first pass, I will break it down step by step later.
package com.vivisectingmedia.example { public class User { // stores our instance static private var __inst:User; // standard public properties public var name:String; public var address:String; public var birthDate:Date; // accessor for the instance static public function get instance():User { if(!__inst) __inst = new User(generateLock()); return __inst; } // accessor for our SingletonLock static protected function generateLock():SingletonLock { return SingletonLock; } // our constructor, must be public in AS3 public function User(lock:Class) { if(!lock is SingletonLock) { throw new Error("Invalid use of singleton."); } } // add public methods and such here public function get age():int { // calculate age and return it ... } ... } } class SingletonLock { public function SingletonLock() { } }
Let’s break this down step by step. First of all lets look at the static property __inst and the static method instance(). These two parts are the most important aspect of the Singleton pattern. So what are we doing in instance()? The first thing to notice is that the instance() method is both static and a getter with no setter which makes it read-only. We would use it like this:
// set the user's info and call the age() method User.instance.name = "Fred"; User.instance.address = "123 Mission St." User.instance.birthData = new Date(1978, 5, 14); var age:int = User.instance.age;
What happens is we call the instance() method through the class reference of User, the instance() method then looks and sees if the __inst property is currently storing an instance of User, if not then we create a new instance of User, save it in __inst and then return the reference. This means the the second time we call instance on the User class, we have already created the instance of User and we just hand back the reference. That’s the magic of the Singleton right there, we now only have one instance of the class that is created exactly once and is created at the time you need it. You don’t need to worry about creating it in onCreationComplete() or in the Document class. The first time you access it the item creates itself. Pretty nifty, eh?
So what is all the other crap that is in this class? The rest of the code is both designed to help enforce Singleton usage in ActionScript and allow extending of the Singleton Class.
Protecting Singletons in ActionScript
One of the current limitations of AS3 is that constructors have to be public. In languages like Java they can be marked protected but not in AS3. This is being resolved in the ECMA 4 standard so when the new version of AS comes out we will not longer have to put all this enforcement code in.
Because constructors are always public there is nothing stopping a developer from ignoring the static instance getter and just creating an instance of the User class locally. This is a bad thing because we now have multiple instances of the object and this defeats the Singleton pattern. To help enforce this we use the SingletonLock as a special key that prevents the constructor from being used EXCEPT in instance() call and/or the extension process (more on extending later). Let’s look at the constructor again:
// our constructor, must be public in AS3 public function User(lock:Class) { if(!lock is SingletonLock) { throw new Error("invalid use of singleton."); } }
You will notice that the constructor expects one argument of type Class and then checks to make sure the passed in Class is of type SingletonLock, if not we throw an Error. SingletonLock is an internal class that is ONLY available to the User Class. We expose this class through a method called generateLock() which hands back the Class reference to the internal Class. The instance() method uses generateLock() to create the lock and pass it on to the constructor. By setting this structure up we have created an enforcement policy that only allows Classes with access to generateLock() to create an instance of the class. Take a moment to go back and walk through the entire User Class to make sure you understand this creation flow.
Its seems like overkill, but this kind of code is very important when working with open source projects or large teams. It forces developers to follow the pattern and prevents improper use of a Singleton based class. As I mentioned earlier this is only because AS3 does not allow protected or private constructors. In the future we can throw all this enforcement code away, but for now we should use it.
Extending A Singleton
Now that we have the Singleton how can we extended it and why would we ever want to? Very rarely would you want to extend a Singleton but it does come up. For me, the number one reason I want to extend Singletons is for automated unit testing.
Here is the situation: I have a series of unit tests that I want to run and each of the tests need to assume a clean instance of the Singleton exists. The challenge is that the tests all run in the same instance of the application (FlexUnit) and therefor the Singleton is created on the first test and the second test is now manipulating the previously created Singleton. Very bad for a testing environment.
One solution is that we expose a reset() method on the Singleton that enables the unit test to reset the Singleton instance. This is a bad approach because we really don’t want to expose this public method in the live version because we want to prevent users for resetting the Singleton, this reset() method is only for testing purposes.
The ideal solution is to extend the Singleton in the Test Suite and add the reset() method which is called on tearDown(). The test would use the extended instance so we are now able to verify the core Singleton functionality and still get reset() without exposing it for the deployed version. Here is how we would create a TestUser that extends our User example:
package com.vivisectingmedia.example { public class TestUser extends User { // stores our instance static private var __inst:TestUser; // accessor for the instance static public function get instance():TestUser { if(!__inst) __inst = new TestUser(generateLock()); return __inst; } static public function reset():void { __inst = new TestUser(generateLock()); } // our constructor, must be public in AS3 public function TestUser(lock:Class) { super(lock); } } }
What changed? First we still define the static private instance but we type it as TestUser. The value has to be private because the __inst has to be specific to the Class its defined in. Remember that static properties and methods are bound to the Class itself. Things get a little tricky here so let me see if I can explain it.
We could try and set __inst as protected property on the User class. When the user calls instance() on TestUser we could create the TestUser instance, store it in the the protected __inst version on User since TestUser is a User. We could then cast __inst as a TestUser for the return call.
// accessor for the instance static public function get instance():TestUser { if(!__inst) __inst = new TestUser(generateLock()); return TestUser(__inst); }
The problem with this approach is that if you called User.instance first then tried TestUser.instance you will get an error because __inst is holding the User instance and User can not be upcasted to TestUser. The solution is to keep the __inst separate in each Class to prevent this possible issue. The added benefit is that you can have a User instance and TestUser instance living side by side which is awesome if you are extending the Singleton for other purposes.
The next thing we did is redefined instance(). Notice how I did not have to use override? Static methods are bound only to the Class and not any children that extend the Class. We have to redefine it to expose it on TestUser. Also, notice that the code is creating a TestUser and passing in the parents protected generateLock() call. Make sure to look at how we changed the constructor. We still expect the lock and we pass the generated lock on the to the super call.
This is exactly why we use a generateLock() method and pass a Class reference around. Up to this point a lot of developers (myself included) used the following style for defining the constructor:
// accessor for the instance static public function get instance():User { if(!__inst) __inst = new User(new SingletonLock()); return __inst; } // our constructor, must be public in AS3 public function User(lock:SingletonLock) { ... }
The issue with this structure is that you can not extend User because the constructor signature requires knowledge of the SingletonLock class which is an internal class of User and therefore only User can access it. By replacing the lock as a Class we can still secure the Singleton by validating the passed lock but we can easily extend it since we are expecting type Class in place of type SingletonLock.
Now that we have fully extended out Class we can add our reset() method which then overwrites the __inst. That’s how you can build and extend singletons in ActionScript. As always please let me know if you see any errors or have any questions about how this all works.
You must be logged in to post a comment.