Recipe17.1.Implementing the Singleton Pattern


Recipe 17.1. Implementing the Singleton Pattern

Problem

You want to apply the singleton pattern using AspectJ.

Solution

The Singleton pattern allows the definition of a class as having one runtime instance within an application. A singleton is normally met by providing no default constructor for a particular class, often overridden as a protected constructor, so an object of the class cannot be directly instantiated by the application. Access to the singleton object is usually implemented by creating a static method that returns the single instance of the class.

Example 17-1 shows an abstract aspect that uses the Director aspect-oriented design pattern (see Chapter 23) to provide a generic foundation for applying the singleton pattern.

Example 17-1. Using an aspect to define the Singleton Pattern
public abstract aspect SingletonPattern issingleton( ) {    private Hashtable singletons = new Hashtable( );    public interface Singleton    {    }    public interface NonSingleton    {    }    // Pointcut to define specify an interest in all creations    // of all Classes that extend Singleton    pointcut selectSingletons( ) : call((Singleton +).new (..));    // Pointcut to ensure that any classes in the Singleton inheritance tree    // that are marked as Non Singletons are not included in the Singleton    // logic.    pointcut excludeNonSingletons( ) : !call((NonSingleton +).new (..));    Object around( ) : selectSingletons( ) && excludeNonSingletons( )    {       Class singleton = thisJoinPoint.getSignature( ).getDeclaringType( );       synchronized(singletons)       {          if (singletons.get(singleton) == null)          {             singletons.put(singleton, proceed( ));          }       }                        return (Object) singletons.get(singleton);    } }

Discussion

The SingletonPattern abstract aspect defines two roles: Singleton and NonSingleton. The roles are implemented as interfaces so that the abstract aspect can work with the singletons without worrying about implementation details.

Figure 17-1 shows the structure of the SingletonPattern abstract aspect with the interfaces and behavior that it defines to support the singleton design pattern.

Figure 17-1. The structure of the SingletonPattern abstract aspect


The Singleton interface is applied by subaspects of the abstract SingletonPattern aspect to any classes within the target application that are to be treated as singletons. Similarly, the NonSingleton interface is applied to classes that may pick up singleton behavior from their parent class by inheritance. If you decide the child class is not to be a singleton, then the NonSingleton interface can be employed so that the singleton characteristic of the parent is overridden.

Two pointcuts are declared to capture when classes that have the Singleton interface are instantiated. The selectSingletons( ) pointcut definition picks the calls to the constructors on classes that extend the Singleton interface. To support the need to turn off the singleton behavior for subclasses of singletons, the excludeNonSingletons() pointcut is declared. This pointcut can be overridden by the specific aspects when you need to stop a subclass from being affected by a superclass's singleton behavior.

The around( ) advice captures calls to constructors on classes that have had the Singleton interface applied. The around( ) advice overrides the constructor to check that the type of the object being instantiated has not been created.

A lookup of the object's class being created is performed on the singletons hash table using the class information supplied by the thisJoinPoint variable. If the type of class is not present within the hash table, then its class is added and an object of that class is constructed by calling proceed( ), which executes the original constructors logic. The proceed( ) call returns the constructed object and this is added with the class object to the hash table.

If the type of the class is present within the hash table, then no new objects need to be created. The singleton object is retrieved from the hash map according to its class and returned from the around( ) of advice as the result of the constructor call.

By default, an aspect in AspectJ is a singleton. The SingletonPattern aspect uses the explicit issingleton() instantiation policy to highlight this aspect's important behavioral characteric.

The implementation of the singleton pattern in this recipe is threadsafe because the hash table is locked during the execution of the around( ) advice using a synchronize block for simplicity. This incurs a performance penalty when the singleton is accessed for the first time and created, but it means that the pattern can then be applied within a multithreaded application. A more efficient mechanism could be to use an instance of the ThreadLocal class as a variable inside the aspect to ensure that the locked check is only performed once for a single thread, as discussed in the article by Brian Goetz, available at http://www.javaworld.com/javaworld/jw-11-2001/jw-1116-dcl.html.


Example 17-2 shows how the abstract SingletonPattern aspect can be applied for a specific application.

Example 17-2. Applying the abstract SingletonPattern aspect to target application classes
public aspect PrinterSingleton extends SingletonPattern  {    declare parents: Printer implements Singleton;             declare parents: SpecializedPrinter implements NonSingleton; }

Figure 17-2 shows how the PrinterSingleton aspect affects an applications classes.

Figure 17-2. How the static application structure is affected by the PrinterSingleton aspect


Figure 17-3 shows how the new singleton behavior of the Printer class behaves in an example application.

Figure 17-3. Using the new singleton behavior of the Printer class


See Also

Recipe 13.4 provides more detail on the proceed( ) call and its usage within around( ) advice; Recipe 7.1 describes the call(Signature) pointcut when capturing calls to a classes constructor; more information on aspect instantiation policies is available in Chapter 14; the Director aspect-oriented design pattern is explained in Recipe 23.3.



AspectJ Cookbook
Aspectj Cookbook
ISBN: 0596006543
EAN: 2147483647
Year: 2006
Pages: 203
Authors: Russ Miles

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