|
Evaluating Software Design Patterns — the "Gang of Four" patterns implemented in Java 6 |
||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |
See:
Description
Interface Summary | |
---|---|
SingletonRegistry<T> | A singleton registry is a container for singleton
instances of any type, S , inheriting the common
super type, T . |
Class Summary | |
---|---|
LoadableSingletonRegistry<T> | A loadable singleton registry is a registry that offers
the same functionality as StatefullSingletonRegistry , but
also allows loading of the actual singleton classes if not already
loaded using the LoadableSingletonRegistry.getInstance(String) method. |
Main | Singleton tests. |
MutatedSimpsonsFamilySequence | A mutated Simpsons family sequence is a sequence representing a random mutated sub-set of the primary family members in the one and only The Simpsons family. |
NorwegianAlphabetSequence | A singleton alphabet sequence for letters in the Norwegian alphabet:
a though z as well as æ , ø , and
å , all lower-cased. |
SimpsonsAndBouvierFamilySequence | A Simpsons and Bouvier family sequence is a singleton sequence representing the primary family members in the The Simpsons and Bouvier families. |
SimpsonsAndBouvierFamilySequence.Instance | An instance container class that when loaded will create
the SimpsonsAndBouvierFamilySequence instance to use and return
from the SimpsonsAndBouvierFamilySequence.getFamily() method. |
SimpsonsFamilySequence | A Simpsons family sequence is a singleton sequence representing the primary family members in the one and only The Simpsons family. |
SimpsonsFamilySequence.Instance | An instance container class that when loaded will create
the SimpsonsFamilySequence instance to use and return
from the SimpsonsFamilySequence.getFamily() method. |
SmileySequence | A smiley sequence is a sequence delivering different smileys, e.g. :), *<;), :(, etc. |
StatefullSingletonRegistry<T> | A statefull singleton registry stores a reference to each acquired singleton instance using a live daemon thread: as long as the registry is not garbage collected, the singleton instances acquired through it will not be garbage collected either. |
StatelessSingletonRegistry<T> | A stateless singleton registry is a registry with no
internal state that allows any type annotated correctly
with the Singleton annotation to be fetched, and
possibly created, using the StatelessSingletonRegistry.getInstance(Class)
method. |
Enum Summary | |
---|---|
DanishAlphabetSequence | A singleton alphabet sequence for letters in the Danish alphabet:
a though z as well as æ , ø , and
å , all lower-cased. |
Exception Summary | |
---|---|
SingletonException | A singleton exception is thrown in case a given
type cannot be determined to be a singleton type when requested
from a given registry or in case
a singleton instance cannot be acquired from a registry. |
Error Summary | |
---|---|
SingletonError | A singleton error is thrown because of illegal access to a singleton constructor. |
Annotation Types Summary | |
---|---|
Singleton | A singleton annotation identifies a given type already at compile-time as a singleton by identifying the static method returning an instance of the annotated type. |
Implementations and examples of the Singleton design pattern [Gamma95, p.127].
Intent:
Ensure a class only has one instance, and provide a global point of access to it.
DanishAlphabetSequence
,
NorwegianAlphabetSequence
,
SimpsonsFamilySequence
, and
SimpsonsAndBouvierFamilySequence
classes, all but NorwegianAlphanetSequence
performing lazy
initialisation when the singleton instance is requested. However,
synchronisation is not required in either case because Java's standard
static initialisation procedures are exploited. The
SmileySequence
class, which also
represents the Singleton participant, therefore illustrates
lazy initialisation using synchronisation (see implementation notes
in the class JavaDoc for each singleton type for further information).
Singleton Registry functionality in a manner similar to
that described by Gamma et al. [Gamma95, p.130-133] is also included
in this package. The SingletonRegistry
interface represents such a registry, using class tokens as arguments
to identify a given singleton instance in the registry using
the SingletonRegistry.getInstance(Class)
method. Here, however, registry functionality is independent of
inheritance as the registry is completely separated from actual
singleton types/instances, and registries have no influence over
when and how actual singleton instances are created. Furthermore,
by declaring an interface to implement for required registry functionality,
as opposed to using static methods directly, we get all the standard
benefits of object behaviour and polymorhpism at the cost of having
to create (possibly singleton) registries as well. For example, a
registry implementation may be synchronised or otherwise proxied or
decorated, or used as a private member variable in a factory.
Three SingletonRegistry
implementations are supplied, namely
StatelessSingletonRegistry
,
StatefullSingletonRegistry
, and
LoadableSingletonRegistry
.
All defers the responsibility of creating the singleton objects
elsewhere, either directly to the singleton type or to another registry
(for the last two).
The StatelessSingletonRegistry
is stateless, and can return
singleton types annotated with the
Singleton
annotation. The annotation
identifies the static singleton method used to acquire the
singleton instance, e.g. getInstance()
, and the actual creation
of the singleton instance is thus left up to the actual singleton type.
Different means of singleton initialisation can therefore be employed
"within" the same registry, for example static or lazy initialisation.
Here, an annotation is preferred over an interface, because different
singleton objects offer no common functionality except for conceptual
behaviour in form of only a single instance available. The singleton
method must in any case be static, and interfaces cannot declare static
methods. An annotation also allows for different method names for
different types, which is exemplified by the
NorwegianAlphabetSequence.getInstance()
and SimpsonsFamilySequence.getFamily()
singleton methods.
The StatefullSingletonRegistry
is a singleton registry that
defers the actual acquiring of singleton instances to another
registry, for example StatelessSingletonRegistry
, but keeps
a reference to each singleton instance that is reachable from
a live daemon thread. Hence, as long as the statefull registry is
within scope, all acquired singleton instances will be in scope and
never be garbage collected.
The LoadableSingletonRegistry
extends StatefullSingletonRegistry
to provide even more specialised functionality: singleton classes can be
dynamically loaded (if not already) based on their class name using the
same class loader. The registry only allows singleton types of the
proper generic bounds to loaded as well.
Implementation notes:
Any singleton instance in Java is only a singleton per class loader
if created based on and utilising intrinsic class features.
Java does not support multiple functional inheritance. Inheriting private functionality is not possible. Hence, to allow a singleton type to be sub-classed as discussed by Gamma et al. [Gamma95, p.128,130-132], an access modifier of either public or protected must be used for the class, behaviour, and data to be inherited. Any context can access public elements, while members in the same package or sub-classes can access protected elements. This poses potential problems because if a constructor in a singleton class is not declared private, it may be accessed by a given context. Even worse, using reflection, even private members can be accessed if the security manager allows it. Hence, declaring a constructor private is no guarantee that it cannot be invoked.
To remedy this while still allowing singleton types to be sub-classed,
the singleton types declared in this package all use the
CallerClass
or
Caller
class to establish
who the caller of the constructor is; that is, which
class and/or member is invoking the constructor. The classes utilises
Java's reflection capabilities. The idea is that if the constructor
is the private singleton constructor, only the exact same class
is allowed to call it. If a sub-class constructor is called, for
example a sub-class copy constructor, the constructor checks to see
if the caller is a constructor in a sub-class. If so, the call
is allowed, otherwise a SingletonError
exception is thrown. As an example, the
SimpsonsFamilySequence
is a singleton
type that is allowed to be sub-classed. The
SimpsonsAndBouvierFamilySequence
class
inherits it and is also a singleton type itself, while the
MutatedSimpsonsFamilySequence
class
also inherits it, but is not a singleton type itself. We
call types enforcing such runtime access checks for
Guarded Types.
However, it would in fact be possible to create a super-singleton
instance from a sub-class constructor! A Caller
cannot
determine how the super-class constructor is invoked from a
sub-class, only from where. In the sub-class constructor,
the super-constructor could be invoked as super(..)
as
would be expected, but also by explicitly creating a new instance
using new
. It does not help to declare the super-singleton
type as abstract. Hence, any singleton type that allows sub-classing
has to trust the sub-classes to some extent, but must common misuse
can be caught with the CallerClass
and Caller
classes.
An alternative is to use enumerations with a single constant to represent
a singleton type. This is illustrated with the
DanishAlphabetSequence
implementation.
We call this the
Singleton-as-Single-Constant idiom.
No synchronisation is used in singleton types or in registries!
|
Gunni Rode / rode.dk | ||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |