CSC/ECE 517 Fall 2010/ch3 3f sm

From Expertiza_Wiki
Jump to navigation Jump to search

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

  1. Ruby documentation for Singleton module
  2. http://en.wikipedia.org/wiki/Singleton_pattern
  3. http://www.javabeginner.com/learn-java/java-singleton-design-pattern
  4. Head First Java book