CSC/ECE 517 Fall 2010/ch3 3f sm: Difference between revisions
(9 intermediate revisions by the same user not shown) | |||
Line 9: | Line 9: | ||
The definiton can be explained as "we can have one and only one instance of the class". Singleton pattern is useful in cases where you need to interact with input and output devices, | The definiton can be explained as "we can have one and only one instance of the class". Singleton pattern is useful in cases where you need to interact with input and output devices, | ||
to maintain thread pools, to log events in a single log file etc. Although the class diagram of the singleton class seems simple, | to maintain thread pools, to log events in a single log file etc. Although the class diagram of the singleton class seems simple, | ||
it's implementation can be quite a task. | it's implementation can be quite a task. Its unique behavior of having just one object and serving up the same object whenever requested makes it so. | ||
Classes are naturally designed in a way that we create many instances of them. So we have to | Classes are naturally designed in a way that we create many instances of them. So we have to go against this notion and make sure we have only one object. | ||
We have to take care of multi-threading scenarios, subclassing etc. | We have to take care of multi-threading scenarios, subclassing etc. All these constraints make implementation of singleton pattern in [http://en.wikipedia.org/wiki/Dynamic_programming_language dynamic] and static languages interesting. | ||
==Singleton Pattern in Java== | ==Singleton Pattern in Java== | ||
Java is a statically typed object oriented language. Among other things this means that type checking is done | Java is a statically typed object oriented language. Among other things, this means that type checking is done during [http://en.wikipedia.org/wiki/Compile_time compile time] in Java. | ||
<br/><br/> | <br/><br/> | ||
'''Implementation''' | '''Implementation''' | ||
:Singleton pattern in | :Singleton pattern in Java is implemented considering the 4 steps mention below: | ||
*Create a default constructor and make it private. | *Create a default [http://en.wikipedia.org/wiki/Constructor_(object-oriented_programming) constructor] and make it private. | ||
*Create a method for getting the reference to the singleton object. | *Create a method for getting the reference to the singleton object. | ||
* Make the access method synchronized to prevent thread issues. | * Make the access method synchronized to prevent thread issues. | ||
* Prevent cloning of the object by overriding the object clone method. | * Prevent cloning of the object by [http://en.wikipedia.org/wiki/Method_overriding overriding] the object clone method. | ||
<pre> | <pre> | ||
class SingletonObject { | class SingletonObject { | ||
Line 39: | Line 39: | ||
</pre> | </pre> | ||
In this code we have followed the first two steps. We are making the default constructor private. This means that the constructor can be accessed only by other methods | In this code we have followed the first two steps. We are making the default constructor private. This means that the constructor can be accessed only by other methods | ||
inside the class. | inside the class. It prevents a developer from creating an object of the class by using this line of code - ''''SingletonObject myObject = new SingletonObject()''''. To get the object of the singleton class | ||
the developer must call the ''SingletonObject.instance()'' method. In the instance method a new object is | the developer must call the ''SingletonObject.instance()'' method. In the instance method a new object is created if a singleton object doesn’t exist, otherwise the existing | ||
reference to ''SingletonObject'' is returned. This way the reference to same object is returned every time the instance method is called. In the above example we are using lazy | reference to ''SingletonObject'' is returned. This way the reference to same object is returned every time the instance method is called. In the above example we are using [http://en.wikipedia.org/wiki/Lazy_initialization lazy instantiation] which means that the object is created only when the initialize method is called for the first time. We could have also used early instantiation. In that case, | ||
instantiation | |||
the object would be instantiated when the class is loaded. | the object would be instantiated when the class is loaded. | ||
<br /> <br /> | |||
'''Synchronization and Cloning''' | |||
<br /> | |||
The above code seems to be good enough for a singleton pattern, but when we take a closer look we realize that when multiple threads access this instance method | |||
there is a possibility that more than one object can get created. So we need to make this method synchronized. This makes sure that only one thread can | |||
access this function at a time and ensures that only one object is ever created of the SingletonObject class. Synchronizing the singleton method has | |||
some consequences. This may result in performance loss if the singleton instance method is being accessed a lot of times in our over all application. | |||
This may be the case in some singletons which manage I/O operations, write logs to the same file etc. A closerlook at the code can tell us that | |||
synchronizing access to the ''instance()'' method is not necessary after the object is created, that is after the first call to the ''initialize()'' method. So, instead of synchronizing the whole method we could just synchronize the block of code which creates the new object. | |||
<pre> | <pre> | ||
class SingletonObject { | class SingletonObject { | ||
Line 63: | Line 72: | ||
} | } | ||
</pre> | </pre> | ||
We can still create a copy of the singleton by cloning it using the Object’s clone method. | We can still create a copy of the singleton by cloning it using the Object’s clone method. | ||
It can be done | It can be done using this line of code - ''''SingletonObject clonedObject = (SingletonObject) obj.clone();''''. | ||
To avoid this we have to override the clone method as shown above. We can just throw an exception when this method is called. | To avoid this we have to override the clone method as shown above. We can just throw an exception when this method is called. | ||
Line 79: | Line 80: | ||
Ruby is a dynamically typed object oriented language. This means type checking happens at run time. Implementing the singleton pattern in | Ruby is a dynamically typed object oriented language. This means type checking happens at run time. Implementing the singleton pattern in | ||
Ruby has the same | Ruby has the same constraints as in Java. So we can write the ruby equivalent of the code above and we will have the Ruby singleton pattern. | ||
<pre> | <pre> | ||
Line 97: | Line 98: | ||
end | end | ||
</pre> | </pre> | ||
This is how singleton is implemented in ruby. In this case we are using | This is how singleton is implemented in ruby. In this case we are using early instantiation as you can see. We might have to lock the instance method with [http://ruby-doc.org/core/classes/Mutex.html mutex]. Even though the code seems smaller and simpler compared to Java's implementation, it is still a lot of things to do. So, Ruby provides a simpler way to do it. [http://ruby-doc.org/stdlib/ Ruby standard library] has a [http://ruby-doc.org/stdlib/libdoc/singleton/rdoc/index.html singleton module] which we can use. | ||
It defines the initialize method for us. It does lazy instantiation of the singleton object too. | It defines the initialize method for us. It does lazy instantiation of the singleton object too. | ||
Line 110: | Line 110: | ||
The include Singleton statement in the above code includes all the methods of the Singleton module. The instance method we saw in the previous example is implemented in the | The include Singleton statement in the above code includes all the methods of the Singleton module. The instance method we saw in the previous example is implemented in the | ||
Singleton module | Singleton module. | ||
==Conclusion== | ==Conclusion== | ||
Line 118: | Line 118: | ||
Implementation of singleton pattern mostly decides on what tradeoff we are ready to make. If we dont call the initialize method too many times then we can make do with having | Implementation of singleton pattern mostly decides on what tradeoff we are ready to make. If we dont call the initialize method too many times then we can make do with having | ||
it being synchronized. If lazy instantiation is necessary then we have to tradeoff the convinience that comes with using static variables. | it being synchronized. If lazy instantiation is necessary then we have to tradeoff the convinience that comes with using static variables. | ||
Nevertheless, since Ruby provides us a standard library module to code a Singleton pattern, the implementation is simplified to a great extent when compared to Java. As seen above, the complexity of the code and the number of lines needed for the implementation of the Singleton pattern is drastically reduced using the Singleton module of the Ruby standard library. | |||
==References== | ==References== | ||
#[http://ruby-doc.org/stdlib/libdoc/singleton/rdoc/index.html Ruby documentation for Singleton module] | |||
#http://en.wikipedia.org/wiki/Singleton_pattern | |||
#http://www.javabeginner.com/learn-java/java-singleton-design-pattern | |||
#[http://oreilly.com/catalog/9780596007126 Head First Java book] | |||
Latest revision as of 04:10, 14 October 2010
Introduction
Singleton pattern has the simplest class diagram among all the design patterns discussed by the gang of four. It has just one class. It has some interesting characteristics. Lets start with the definition itself.
- Singleton
- Ensures a class has only one instance, and provides a global point of access to it.
The definiton can be explained as "we can have one and only one instance of the class". Singleton pattern is useful in cases where you need to interact with input and output devices, to maintain thread pools, to log events in a single log file etc. Although the class diagram of the singleton class seems simple, it's implementation can be quite a task. Its unique behavior of having just one object and serving up the same object whenever requested makes it so. Classes are naturally designed in a way that we create many instances of them. So we have to go against this notion and make sure we have only one object. We have to take care of multi-threading scenarios, subclassing etc. All these constraints make implementation of singleton pattern in dynamic and static languages interesting.
Singleton Pattern in Java
Java is a statically typed object oriented language. Among other things, this means that type checking is done during compile time in Java.
Implementation
- Singleton pattern in Java is implemented considering the 4 steps mention below:
- Create a default constructor and make it private.
- Create a method for getting the reference to the singleton object.
- Make the access method synchronized to prevent thread issues.
- Prevent cloning of the object by overriding the object clone method.
class SingletonObject { private static SingletonObject myObject; private SingletonObject() { // Optional Code } public static SingletonObject getSingletonObject() { if (myObject == null) { myObject = new SingletonObject(); } return myObject; } }
In this code we have followed the first two steps. We are making the default constructor private. This means that the constructor can be accessed only by other methods
inside the class. It prevents a developer from creating an object of the class by using this line of code - 'SingletonObject myObject = new SingletonObject()'. To get the object of the singleton class
the developer must call the SingletonObject.instance() method. In the instance method a new object is created if a singleton object doesn’t exist, otherwise the existing
reference to SingletonObject is returned. This way the reference to same object is returned every time the instance method is called. In the above example we are using lazy instantiation which means that the object is created only when the initialize method is called for the first time. We could have also used early instantiation. In that case,
the object would be instantiated when the class is loaded.
Synchronization and Cloning
The above code seems to be good enough for a singleton pattern, but when we take a closer look we realize that when multiple threads access this instance method
there is a possibility that more than one object can get created. So we need to make this method synchronized. This makes sure that only one thread can
access this function at a time and ensures that only one object is ever created of the SingletonObject class. Synchronizing the singleton method has
some consequences. This may result in performance loss if the singleton instance method is being accessed a lot of times in our over all application.
This may be the case in some singletons which manage I/O operations, write logs to the same file etc. A closerlook at the code can tell us that
synchronizing access to the instance() method is not necessary after the object is created, that is after the first call to the initialize() method. So, instead of synchronizing the whole method we could just synchronize the block of code which creates the new object.
class SingletonObject { private static SingletonObject myObject; private SingletonObject() { // Optional Code } public static synchronized SingletonObjec myObject() { if (myObject == null) { myObject = new SingletonClass(); } return myObject; } public Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } }
We can still create a copy of the singleton by cloning it using the Object’s clone method. It can be done using this line of code - 'SingletonObject clonedObject = (SingletonObject) obj.clone();'. To avoid this we have to override the clone method as shown above. We can just throw an exception when this method is called.
Singleton pattern in Ruby
Ruby is a dynamically typed object oriented language. This means type checking happens at run time. Implementing the singleton pattern in Ruby has the same constraints as in Java. So we can write the ruby equivalent of the code above and we will have the Ruby singleton pattern.
class SingletonObject def initialize #option code end @@instance = SingletonObject.new def self.instance return @@instance end private_class_method :new end
This is how singleton is implemented in ruby. In this case we are using early instantiation as you can see. We might have to lock the instance method with mutex. Even though the code seems smaller and simpler compared to Java's implementation, it is still a lot of things to do. So, Ruby provides a simpler way to do it. Ruby standard library has a singleton module which we can use. It defines the initialize method for us. It does lazy instantiation of the singleton object too.
require 'singleton' class SingletonObject include Singleton end
The include Singleton statement in the above code includes all the methods of the Singleton module. The instance method we saw in the previous example is implemented in the Singleton module.
Conclusion
Singleton pattern in both languages as seen above has to take care of a lot of implementation details. It is counter intuitive to the concept of objects and classes. For example subclassing is another important thing to remember when we use the singleton pattern. We cannot subclass the singleton class as it may lead to duplication, unnecessary consequences in the lower classes etc. Implementation of singleton pattern mostly decides on what tradeoff we are ready to make. If we dont call the initialize method too many times then we can make do with having it being synchronized. If lazy instantiation is necessary then we have to tradeoff the convinience that comes with using static variables.
Nevertheless, since Ruby provides us a standard library module to code a Singleton pattern, the implementation is simplified to a great extent when compared to Java. As seen above, the complexity of the code and the number of lines needed for the implementation of the Singleton pattern is drastically reduced using the Singleton module of the Ruby standard library.
References
- Ruby documentation for Singleton module
- http://en.wikipedia.org/wiki/Singleton_pattern
- http://www.javabeginner.com/learn-java/java-singleton-design-pattern
- Head First Java book