The Singleton pattern provides a global means to access a unique object while ensuring the extensibility of that object. Figure 6-8 shows the class diagram.
This pattern has the following parts: Concrete singleton
•
Singleton interface •
Abstract Factory Method pattern • Abstract product • Concrete product • Abstract creator • Concrete creator • Client •
The pattern’s benefits are as follows: Grants global access to an object •
Maintains access to its unique instance •
Reduces the need for multiple global variables •
Permits subclasses •
It also has this drawback: Requires configuration •
A Comprehensive Look
The singleton is an object that enables access to a specific location in memory that preserves the integrity of an OO system. Rather than stitch a series of variables throughout an application, the Singleton pattern provides an ingenious to create and retrieve an instance.
The Singleton design pattern ensures that a particular object can have exactly one instance and one instance only, unless specified otherwise. To ensure the single instance, the sole means of instantiating an object is through the pattern. This prevents the instance from being modified anywhere else in the code. The added benefit is that the singleton becomes the exclusive access point from which the object can be acquired for use.
Using the Singleton pattern also provides flexibility through the use of inheritance. Although each object that uses the Singleton is required to remain a unique instance, the ability to be subclassed can’t be denied. This would be counterproductive given the open-closed design principle.
Vignette
The proprietor of the world’s best fried chicken, whom you met in the last example, continues to search for a way to bring his chicken to everyone in the world. The answer comes to him after he wakes from a terrible dream in which he couldn’t enhance his product without having to enter into new contracts. This was because he ensured that his products would never change, but he wasn’t the enforcer between his product and the clients.
With this realization, the chef decides to take charge of ensuring that he is the contract’s access point for those who want to taste his chicken. This way, he can improve his recipe and ensure that the changes are made without adding confusion among consumers. His name will become synonymous with slogan “The ONLY world’s best chicken”, and he’ll make sure of that.
The AS3 Cast
In AS3, the Singleton pattern’s parts are as follows:
Abstract creator: Defines the type that is used in its particular factory. •
Concrete creator: A factory subclass that contains the logic necessary to instantiate the •
appropriate object in a genus of products expected by the superclass.
Abstract product: Exposes the interface that all concrete products of the given genus inherit. •
Concrete product: Extends the abstract product to express itself as a member of the type to be •
used in the logic of the creator.
Singleton interface: Exposes the contract by which the client can obtain the unique instance. •
The interface possesses a unique method that acts as a wrapper around a class member instance.
Concrete singleton: Implements the behaviors and necessary factories to use. •
Class member Instance: A reference associated with the class and not the object. This reduces •
memory allocation given any number of instances of a given class. Although public, a class member can be accessed in a manner that doesn’t require an instance. You get such a class reference using the static modifier.
Client: Any aspect of the application or system that has prior knowledge of the abstract •
product, as well as the fully qualified name of the singleton class and its static method.
When It’s Useful
The Singleton pattern is useful in these situations:
When exactly one instance of an object in an application is required •
When you need global access to solve a workflow issue (analytics, managers, etc.) •
Example
The Singleton pattern structures code so that while enforcing a unique instance of an object, it lets a subclass become that unique instance, without requiring modification of existing code. A secondary role of the Singleton pattern is to reduce the number of global variables in an application by consolidating namespaces. To achieve such flexibility among unique instances, the structure of the singleton relies on uniform creation via parameterization. You create varying products by using a unified process: the abstract factory.
Although FaceBookExtendedProfile and FaceBook from Listing 6-27 and Listing 6-29 have varying
implementations, they don’t have different interfaces. Therefore, although these interfaces don’t exhibit change, they should be interchangeable in a singleton’s instance. You know that to achieve the singleton’s global access, you use a static method. And because class methods can only reference class members, you need to hold the reference as a static member. Any message to your static method must return the object referenced by the static member _instance. In order to ensure that _instance points to a reference, you need a conditional statement, which you saw earlier in the discussion of the Simple Singleton pattern. This gives you global access to an object of a unique instance, intended for use in the application.
Listing 6-31 shows the internal mechanism of the FaceBookSingleton instance, which currently lacks an interface and an object to instantiate. To maintain flexibility, you need to parameterize an object to be instantiated by the getInstance method, while maintaining anonymity for the object to create. At the same time, you expose a
Listing 6-31. Internals of the FaceBookSingleton object
package {
public class FaceBookSingleton {
static private var $_instance : _____; static public function getInstance() : _____; { if ( !$_instance ) { $_instance = new _____; } return $_instance; } } }
You use an the abstract factory to create an interface to create the product. You know the factory must return a given product and that this product is a subclass of a FaceBook interface.
Figure 6-9. The Singleton making use of the Abstract Factory Listing 6-32. FaceBook
package {
[Event(name="Connect", type=" FaceBookEvent")] [Event(name="Complete", type=" FaceBookEvent")] public class FaceBook extends EventDispatcher {
static public const COMPLETE : String = "complete"; static public const CONNECT : String = "connect"; protected var _faceBook : iFaceBook;
protected var _shortProfile : ShortProfileInformation; protected var _hasProfile : Boolean;
public function Login( target : IEventDispatcher = null ) {
_shortProfile = new ShortProfileInformation(); _hasProfile = false;
}
public function init() : void {
_ready = false;
_faceBook = new FaceBookFacade();
// a class that utilizes my FaceBookGraphAPI
_faceBook.addEventListener( FacebookEvent.CONNECT , faceBookConnectHandler ); }
public function get facebook() : IFaceBook {
return _faceBook; }
public function get hasProfile() : Boolean {
return _hasProfile; }
public function get shortProfile() : ShortProfileInformation {
return shortProfile; }
protected function faceBookConnectHandler( event : FacebookEvent ) : void {
} } }
Using FaceBook as an abstract class allows you to declare your interface. Your past classes become subclasses of the new abstraction. By abstracting the two classes, you can extract commonalities and offer default implementations that occur between both concrete classes.
Listing 6-33. FaceBookProfile
package {
public class FaceBookProfile extends FaceBook {
public function FaceBookProfile() {
super( null ); }
override protected function faceBookConnectHandler( event : FacebookEvent ) : void
{
if (event.success) {
FacebookCall( _faceBook.queryUserInformation() ).addEventListener( FacebookEvent.COMPLETE , userInfoLoaded ); dispatchEvent( new FacebookEvent( FacebookEvent.CONNECT ) ); }
}
protected function userInfoLoaded( event : FacebookEvent ) : void {
var aFaceBookCall : FacebookCall = event.target as FacebookCall;
aFaceBookCall.removeEventListener( FacebookEvent.COMPLETE , userInfoLoaded ); dispatchEvent( new FacebookEvent( FacebookEvent.COMPLETE ) );
var profile : ProfileInformation = _faceBook.getUserProfile(); _shortProfile.usrIdentifier = profile.userName; _shortProfile.faceBook = true; _hasProfile = true } } } Listing 6-34. FaceBookExtendedProfile package {
public class FaceBookExtendedProfile extends Facebook {
public function FaceBookExtendedProfile() {
}
protected override function userInfoLoaded( event : FacebookEvent ) : void {
super.userInfoLoaded( event );
var profile : ProfileInformation = _faceBook.getUserProfile(); acquireAvatar( profile.userAvatarURL );
acquireStatus( profile.status ); }
protected function acquireStatus( xml : XML ) : void {
shortProfile.statusXMLlist = xml..user_status; }
protected function acquireAvatar( AvatarURL : String ) : void {
if (AvatarURL.length < 1) {
var bitmapData : BitmapData = new BitmapData( 100 , 100 , true , 0 ); shortProfile.avatar = bitmapData.clone();
return; }
var loader : Loader = new Loader();
loader.contentLoaderInfo.addEventListener( Event.COMPLETE,onAvatarAcquired ); var urlRequest : URLRequest = new URLRequest( AvatarURL );
var ldrContext : LoaderContext = new LoaderContext(); ldrContext.checkPolicyFile = true;
loader.load( urlRequest , ldrContext ); }
private function onAvatarAcquired( event : Event ) : void {
var ldrInfo : LoaderInfo = event.target as LoaderInfo;
ldrInfo.removeEventListener( Event.COMPLETE , onAvatarAcquired ); var ldrContent : Bitmap = ldrInfo.content as Bitmap;
_bitmapData = ldrContent.bitmapData; _shortProfile.avatar = _bitmapData; }
} }
Now that you have your product, you just need to construct the creator and abstract creator that are passed in to the Singleton. This creates an abstraction among passed-in objects that can be used with the Singleton pattern.
All you’re concerned with for this application is the appropriate instantiation of your object, so the abstract creator only has a factory method that returns an instance of FaceBook (see Listing 6-35). And as you know, with factory methods you should use a method containing the prefix make or create. This example uses a method called makeUniqueFB (see Listing 6-36 and Listing 6-37).
Listing 6-35. AFaceBookCreator
package {
public class AFaceBookCreator {
public function makeUniqueFB() : FaceBook {
} } }
Listing 6-36. FaceBookShortProfileFactory subclasses AFaceBookCreator and retains the knowledge of the
concrete class to instantiate, FaceBook package
{
public class FaceBookShortProfileFactory extends AFaceBookCreator {
public override function makeUniqueFB() : FaceBook {
return new FaceBook(); }
} }
Listing 6-37. FaceBookExtendedProfile subclasses AFaceBookCreator and retains the knowledge of the concrete
class to instantiate, FaceBook package
{
public class FaceBookExtendedProfile extends AFaceBookCreator {
override public function makeUniqueFB() : FaceBook {
return new FaceBookExtendedProfile(); }
} }
Finally, you need to enable the factory to be parameterized into a singleton to create the appropriate single instance (see Listing 6-38).
Listing 6-38. FaceBookSinglet on accepts an abstract factory that contains the appropriate product
package {
public class FaceBookSingleton {
static private var $_factory : AFaceBookCreator; static private var $_instance : FaceBook; static public function getInstance() : FaceBook { if ( !$_instance ) { $_instance = $_factory.makeUniqueFB(); } return $_instance; }
static public function setFactory( FBFactory : AFaceBookCreator ) : void { $_factory = FBFactory; } } }
The bolded code in Listing 6-38 adds the behavior required by the Singleton pattern to provide the flexibility required by an OO application. The appropriate factory is supplied to the singleton before the getInstance method. After the factory is passed in, the existing code can remain unchanged and continue to bind itself to the interface of the returned product.
FAQ
Why is this approach better than using the Simple Singleton pattern? •
The immediate answer is the flexibility it offers. In many languages, a static class can’t be overridden, preventing the use of polymorphism. The Simple Singleton pattern ensures that only one object instance is unique, as well as the access point to this object, by inserting this behavior into the object. Doing so gives a class behaviors that let it behave as a wrapper to itself.
By providing its own wrapper to secure itself, the product reduces loose coupling by the client. This reduces any reusable code to the remnants of objects used for a specific project.
Why do other books show the Simple Singleton pattern as the Singleton design pattern? •
The answer is a bit complicated. As I stressed in Chapter 4, design patterns use UML to avoid referring to any specific language. This is because every language is different. Some OO languages use abstractions, whereas others use interfaces; and some allow methods to be
virtual while others must be static.
The language that interprets each pattern plays a large role in how the pattern appears. The most important thing is understanding the problem the pattern solves and not using the model as the only source.
What makes this approach so flexible? •
In short, the pattern’s indirection makes it so flexible. Although this pattern allows unique instances to remain accessible, extendable, and global, it requires a lot of complexity. This indirection can be both good and bad.
Can more than one object be accessed from the singleton? •
Yes, as long as it fits the needs of your application and doesn’t overly complicate the code. The Singleton pattern aims to reduce the number of global variables in an application by allowing them to be acquired from a single access point.
Related Patterns
The following patterns are related to the Singleton pattern: Abstract Factory
•
Builder •
Summary
It’s very easy to overlook the chance to use a creational pattern and fall back on the new keyword. This is a “Get it done” mentality; and although I can sympathize with it as a developer, it doesn’t save you any time on the next project. The quick implementations may be the last nail in the coffin.
This doesn’t mean you should afraid of the keyword new, but consider how important it is for the declaration to be in the body where it resides. This is the deciding factor when you’re considering whether your code should use a creational pattern.
Abstraction is crucial. Specifics are always necessary in an application, but their placement is critical. The design patterns discussed in this chapter rely heavily on abstraction that makes code easier to change.