|
Navigation: Appendix B: Dolphin Pattern Book > Global Variable Patterns > Singleton |
![]() ![]()
|
Context
When creating a New Class it may be apparent that there should only ever be one instance of it. It's too risky to rely on a developer not to create several instances by accident, so a scheme to enforce this criterion is required. An example might be a class which represents the mouse or screen. There should only be a single representation of these devices since that accurately models the real world situation. We must also provide a means of accessing the singleton; ideally without creating a Global Variable in which to store it.
Solution
Make the class itself responsible for managing its single instance.
Implement this by adding a class variable to hold the singleton, and a class method current to answer it. Ensure that the singleton is initialized, either when the application starts, or by using Class Initialization or Lazy Initialization. All access to the singleton should be by sending #current to the class.
You should also, disable the #new method by overriding it to raise an exception. This will prevent programmers from accidentally creating their own, non-singleton, instances of the class.
Examples
An imaginary Mouse class has a class variable called Current which holds the singleton instance. Access to it is allowed only through the current class method which uses Lazy Initialization.
Mouse class>>current
"Answer the singleton instance of the Mouse class."
Current isNil ifTrue: [self current: self basicNew].
^Current
Mouse class>>current: aMouse
"Set the Mouse singleton Current to aMouse."
Current := aMouse
Mouse class>>new
"Mouse is a singleton class. Use #current."
self shouldNotImplement
Consequences
Sometimes you need to create a class which isn't a true singleton, but instead has a commonly used default instance but other instances can potentially exist. In such cases, create the class as if it were a singleton but use #default (by convention) to access the default instance. Don't override #new though, or you won't be able to create any additional instances.
Known Uses
The DesktopView class maintains a singleton instance in the class variable Current, and access to this singleton is provided by the #current class method. DesktopView initializes this during it's Class Initialization.
current
"Answers the singleton instance of the receiver."
^Current
current: aDesktopView
"Sets the singleton instance of the receiver."
Current := aDesktopView
initialize
"Initialize the DesktopView singleton."
Current := self new
assumeDesktopHandle;
yourself
Related Patterns