CSC/ECE 517 Fall 2010/ch3 3f DF: Difference between revisions
(→Usage) |
|||
(77 intermediate revisions by the same user not shown) | |||
Line 4: | Line 4: | ||
== Introduction == | == Introduction == | ||
The Singleton design pattern ensures that there is no more than one instance of an object in existence at a time. This is accomplished by protecting the allocation and deallaction methods of the class to restrict them from general use. Instead of calling these methods directly, all requests for the object are routed through a public interface which only creates the object if it doesn't exist already. Upon creation, the object is stored in a class variable and this single instance is also returned to all future callers. | |||
<center> [[Image:SingletonUML.png]] </center> | |||
== Usage == | |||
The Singleton pattern should only be used in situations where more than a single instance of the class will never be needed. This key point also serves as the main argument against use of the Singleton pattern as it is often mis-used to provide a simple and quick way to implement a global state to satisfy current requirements. As those requirements are likely to evolve in the future to require multiple states, substantial refactoring of the original code may be required to remove dependencies on the singleton. | |||
A common usage of the singleton pattern is for implementing the Factory class in the [http://en.wikipedia.org/wiki/Factory_method_pattern Factory design pattern]. This provides a global entry method for all classes which use the factory. | |||
<pre> | |||
NewObject = Factory::Instance().CreateNewObject(ObjectType) | |||
</pre> | |||
== Static Language Implementation == | == Static Language Implementation == | ||
The code below is an example of a static language (C++) implementation of the Singleton pattern for the MySingleton class. It is important to note that the implementation and usage of the singleton pattern are intertwined in static languages. Thus, if the pattern is desired for seperate classes, it must be implemented for each one individually. | |||
<pre> | <pre> | ||
class MySingleton | class MySingleton | ||
Line 42: | Line 52: | ||
static MySingleton* s_pSingletonObject; | static MySingleton* s_pSingletonObject; | ||
}; | }; | ||
MySingleton::s_pSingletonObject = NULL; | |||
</pre> | </pre> | ||
== Dynamic Language Implementation == | == Dynamic Language Implementation == | ||
Unlike static languages, dnyamic languages often provide pre-defined pattern implementations that may be added to a class. This is made possible by dynamic definitions which allow mixins to access the class variables for each class they are included in. | |||
Below is a dynamic language (Ruby) implementation of the Singleton pattern. | |||
=== Usage === | |||
<pre> | |||
class MySingleton | |||
include Singleton | |||
# Begin interface methods | |||
# ... | |||
# End interface methods | |||
end | |||
</pre> | |||
=== Implementation === | |||
This is the default Singleton module provided by Ruby in [http://ruby-doc.org/stdlib/libdoc/singleton/rdoc/index.html ''singleton.rb'']. In contrast to static languages, the typical programmer need only understand the general concept behind the Singleton pattern rather than the specifics of this implementation. It should be used as a mixin to provide the pattern functionality to a specific class (see above). | |||
<pre> | |||
module Singleton | |||
# disable build-in copying methods | |||
def clone | |||
raise TypeError, "can't clone instance of singleton #{self.class}" | |||
end | |||
def dup | |||
raise TypeError, "can't dup instance of singleton #{self.class}" | |||
end | |||
# default marshalling strategy | |||
def _dump(depth = -1) | |||
'' | |||
end | |||
module SingletonClassMethods | |||
# properly clone the Singleton pattern - did you know | |||
# that duping doesn't copy class methods? | |||
def clone | |||
Singleton.__init__(super) | |||
end | |||
def _load(str) | |||
instance | |||
end | |||
private | |||
# ensure that the Singleton pattern is properly inherited | |||
def inherited(sub_klass) | |||
super | |||
Singleton.__init__(sub_klass) | |||
end | |||
end | |||
class << Singleton | |||
def __init__(klass) | |||
klass.instance_eval { | |||
@singleton__instance__ = nil | |||
@singleton__mutex__ = Mutex.new | |||
} | |||
def klass.instance | |||
return @singleton__instance__ if @singleton__instance__ | |||
@singleton__mutex__.synchronize { | |||
return @singleton__instance__ if @singleton__instance__ | |||
@singleton__instance__ = new() | |||
} | |||
@singleton__instance__ | |||
end | |||
klass | |||
end | |||
private | |||
# extending an object with Singleton is a bad idea | |||
undef_method :extend_object | |||
def append_features(mod) | |||
# help out people counting on transitive mixins | |||
unless mod.instance_of?(Class) | |||
raise TypeError, "Inclusion of the OO-Singleton module in module #{mod}" | |||
end | |||
super | |||
end | |||
def included(klass) | |||
super | |||
klass.private_class_method :new, :allocate | |||
klass.extend SingletonClassMethods | |||
Singleton.__init__(klass) | |||
end | |||
end | |||
end | |||
</pre> | |||
== Variations == | |||
Several differing variations of the Singleton pattern exist which take the core concept and extend it to support specific situations. It should be noted that such variations on the Singleton pattern are much more common in static languages due to the requirement of having to re-implement the pattern for each use. It is possible to achieve the same functionality in dynamically typed languages; however, it is far less intuitive. To do so in Ruby, for example, would require either the implementation of a variation on the provided Singleton module or [http://en.wikipedia.org/wiki/Monkey_patch monkey-patching] it to behave as desired. | |||
=== Multiple Instantiations === | |||
While the Singleton pattern's namesake arises out of there being a "single" instantiation of the class, it is somtimes used to created a fixed number of instantiations. In these situations, the singleton's accessor methods are parameterized to allow callers to specify which instance of the object they desire. | |||
<pre> | <pre> | ||
MySingleton* Instance(unsigned int uiInstanceNumber) | |||
</pre> | |||
=== Lifetime & Scoping=== | |||
The Singleton pattern is also commonly varied by modifying the lifetime of the instaniated object. Some implementations allow for a singleton to exist through the entire application lifetime. Others, such as the window state manager below, dynamically create and destroy the singleton as needed. | |||
<pre> | |||
class MyWindow | |||
{ | |||
Open() | |||
{ | |||
MyStateSingleton::Instance(); | |||
} | |||
Close() | |||
{ | |||
MyStateSingleton::Destroy(); | |||
} | |||
} | |||
</pre> | </pre> | ||
== References == | == References == | ||
[http://ruby-doc.org/stdlib/libdoc/singleton/rdoc/index.html singleton.rb - Official Ruby Documentation] | |||
[http://en.wikipedia.org/wiki/Singleton_pattern Singleton Pattern - Wikipedia] | |||
[http://en.wikipedia.org/wiki/Factory_method_pattern Factory Design Pattern - Wikipedia] | |||
[http://en.wikipedia.org/wiki/Monkey_patch Monkey Patching - Wikipedia] | |||
[http://www.ibm.com/developerworks/webservices/library/co-single.html Rainsberger, J. B. ''Use Your Singletons Wisely''. IBM Developer. July 2001] | |||
[http://code.google.com/p/google-singleton-detector/wiki/WhySingletonsAreControversial ''Why Singletons Are Controversial''. IBM Developer Works. Feb 2010] |
Latest revision as of 23:58, 15 October 2010
The Singleton pattern in static and dynamic languages
Introduction
The Singleton design pattern ensures that there is no more than one instance of an object in existence at a time. This is accomplished by protecting the allocation and deallaction methods of the class to restrict them from general use. Instead of calling these methods directly, all requests for the object are routed through a public interface which only creates the object if it doesn't exist already. Upon creation, the object is stored in a class variable and this single instance is also returned to all future callers.
Usage
The Singleton pattern should only be used in situations where more than a single instance of the class will never be needed. This key point also serves as the main argument against use of the Singleton pattern as it is often mis-used to provide a simple and quick way to implement a global state to satisfy current requirements. As those requirements are likely to evolve in the future to require multiple states, substantial refactoring of the original code may be required to remove dependencies on the singleton.
A common usage of the singleton pattern is for implementing the Factory class in the Factory design pattern. This provides a global entry method for all classes which use the factory.
NewObject = Factory::Instance().CreateNewObject(ObjectType)
Static Language Implementation
The code below is an example of a static language (C++) implementation of the Singleton pattern for the MySingleton class. It is important to note that the implementation and usage of the singleton pattern are intertwined in static languages. Thus, if the pattern is desired for seperate classes, it must be implemented for each one individually.
class MySingleton { public: static MySingleton* Instance() { if(s_pSingletonObject == NULL) s_pSingletonObject = new MySingleton; return s_pSingletonObject; } static void Destroy() { if(s_pSingletonObject != NULL) { delete s_pSingletonObject; s_pSingletonObject = NULL; } } //Begin interface functions //... //End interface functions private: //Direct access to the constructor/destructor is prohibited MySingleton() {} virtual ~MySingleton() {} static MySingleton* s_pSingletonObject; }; MySingleton::s_pSingletonObject = NULL;
Dynamic Language Implementation
Unlike static languages, dnyamic languages often provide pre-defined pattern implementations that may be added to a class. This is made possible by dynamic definitions which allow mixins to access the class variables for each class they are included in.
Below is a dynamic language (Ruby) implementation of the Singleton pattern.
Usage
class MySingleton include Singleton # Begin interface methods # ... # End interface methods end
Implementation
This is the default Singleton module provided by Ruby in singleton.rb. In contrast to static languages, the typical programmer need only understand the general concept behind the Singleton pattern rather than the specifics of this implementation. It should be used as a mixin to provide the pattern functionality to a specific class (see above).
module Singleton # disable build-in copying methods def clone raise TypeError, "can't clone instance of singleton #{self.class}" end def dup raise TypeError, "can't dup instance of singleton #{self.class}" end # default marshalling strategy def _dump(depth = -1) '' end module SingletonClassMethods # properly clone the Singleton pattern - did you know # that duping doesn't copy class methods? def clone Singleton.__init__(super) end def _load(str) instance end private # ensure that the Singleton pattern is properly inherited def inherited(sub_klass) super Singleton.__init__(sub_klass) end end class << Singleton def __init__(klass) klass.instance_eval { @singleton__instance__ = nil @singleton__mutex__ = Mutex.new } def klass.instance return @singleton__instance__ if @singleton__instance__ @singleton__mutex__.synchronize { return @singleton__instance__ if @singleton__instance__ @singleton__instance__ = new() } @singleton__instance__ end klass end private # extending an object with Singleton is a bad idea undef_method :extend_object def append_features(mod) # help out people counting on transitive mixins unless mod.instance_of?(Class) raise TypeError, "Inclusion of the OO-Singleton module in module #{mod}" end super end def included(klass) super klass.private_class_method :new, :allocate klass.extend SingletonClassMethods Singleton.__init__(klass) end end end
Variations
Several differing variations of the Singleton pattern exist which take the core concept and extend it to support specific situations. It should be noted that such variations on the Singleton pattern are much more common in static languages due to the requirement of having to re-implement the pattern for each use. It is possible to achieve the same functionality in dynamically typed languages; however, it is far less intuitive. To do so in Ruby, for example, would require either the implementation of a variation on the provided Singleton module or monkey-patching it to behave as desired.
Multiple Instantiations
While the Singleton pattern's namesake arises out of there being a "single" instantiation of the class, it is somtimes used to created a fixed number of instantiations. In these situations, the singleton's accessor methods are parameterized to allow callers to specify which instance of the object they desire.
MySingleton* Instance(unsigned int uiInstanceNumber)
Lifetime & Scoping
The Singleton pattern is also commonly varied by modifying the lifetime of the instaniated object. Some implementations allow for a singleton to exist through the entire application lifetime. Others, such as the window state manager below, dynamically create and destroy the singleton as needed.
class MyWindow { Open() { MyStateSingleton::Instance(); } Close() { MyStateSingleton::Destroy(); } }
References
singleton.rb - Official Ruby Documentation
Factory Design Pattern - Wikipedia
Rainsberger, J. B. Use Your Singletons Wisely. IBM Developer. July 2001
Why Singletons Are Controversial. IBM Developer Works. Feb 2010