CSC/ECE 517 Fall 2007/wiki1b 6 aa: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
Line 96: Line 96:
class People
class People
  def pollute(a)  # pollute an earth object
  def pollute(a)  # pollute an earth object
a.currentCondition="i am old and polluted"
  a.currentCondition="i am old and polluted"
end
end


def test
def test
p=People.new
  p=People.new
earth1=Earth.instance
  earth1=Earth.instance
earth2=Earth.instance
  earth2=Earth.instance


earth1.currentCondition="I am young and clean"
  earth1.currentCondition="I am young and clean"
puts "Earth1 says: " + earth1.currentCondition
  puts "Earth1 says: " + earth1.currentCondition
puts "Earth2 says: " + earth2.currentCondition
  puts "Earth2 says: " + earth2.currentCondition
  # pollute earth1
  p.pollute(earth1)
  puts "After people pollute earth1"


# pollute earth1
  puts "Earth1 says: " + earth1.currentCondition
p.pollute(earth1)
  puts "Earth2 says: " + earth2.currentCondition
puts "After people pollute earth1"
end
 
puts "Earth1 says: " + earth1.currentCondition
puts "Earth2 says: " + earth2.currentCondition
end
end
end


p=People.new
p=People.new
p.test
p.test
</pre>
</pre>



Revision as of 02:04, 1 October 2007

By Qinyi Ding (qding@ncsu.edu) and Xibin Gao (xgao2@ncsu.edu)

Take a case of the Singleton pattern and implement it as succinctly as possible in Ruby and Java.Compare the two implementations in terms of clarity and succinctness.The example should be a "real-world" example. While it may be grossly oversimplified for the purpose of illustration, it should not be totally contrived (i.e., should not raise the question, Why would anyone ever want to do that?).


Singleton Pattern

Definition

The singleton pattern is a kind of design pattern in software engineering. Singleton pattern limits the instantiation of a class to only one object to ensure that no other instantiation exists. Therefore this pattern is useful when the system needs only one instance of a class but multiple accesses from different parts of the system.

Singleton Versus Static Variable

At first glance, one might be tempted to create an instance of a counter class as a just a static global variable. This is a common technique but really only solves part of the problem; it solves the problem of global accessibility, but does nothing to ensure that there is only one instance of the class running at any given time. The responsibility of having only one instance of the class should fall on the class itself and not on the user of the class. The users of the class should always be free from having to monitor and control the number of running instances of the class.

Pros and Cons of Singleton Pattern

Implementation

Let's take the example of the Earth. Because we only have one earth, it is proper to implement the Earth class as a singleton. Inside the class, "currentCondition" describes the state (current condition) of the earth.

Ruby Implementation

require 'Singleton'

class Earth
  include Singleton  # include singleton mixin
  attr_accessor :currentCondition
end

Java Implementation


public class Earth {
	  private Earth()
	  {
	   // override the contructor to make it private
	  }
	  private static Earth ref;

	  // make the method thread safe
	  public synchronized static Earth getEarth()
	  {
	    if (ref == null)
            synchronized (Earth.class) {   // for thread-safety
                if (ref == null) ref = new Earth ( );
          } 	
	    return ref;
	  }
          // override the clone method and throws "CloneNotSupported Exception" if invoked
	  public Object clone()
		throws CloneNotSupportedException
	  {
	    throw new CloneNotSupportedException(); 
	  }

	  private String currentCondition="I was beautiful and clean";
	  // get the current condition of the earth
	  public String getCurrentCondition(){
		  return currentCondition;
	  }
	  // set the current condition of the earth
	  public void setCurrentCondition(String str){
		  currentCondition=str;
	  }
	  
	}

Comparison

Ruby can implement singleton pattern by simply referencing the singleton module and all its methods will be included. The singleton mixin makes the constructor inaccessible, overrides clone and dup methods, and takes care of all the threading complications.

Java has no mixins, so singleton implementation in Java has to do the following:

  1. block off access to constructor by making it private
  2. provide a static method for getting an instance of the singleton,
  3. prevent cloning by overriding the clone() method explicitly
  4. ensure thread safety

In terms of succinctness, Ruby obviously wins over Java. Only one line of code "include Singleton" enabled all the functionalities that java use a dozen of lines to accomplish.

In terms of clarity, Ruby also surpasses Java. For Ruby, after including singleton mixin, it is ready to create/get the only object using "instance" method. However, in Java, there is no uniform method to create/get the only object of the singleton class, because it's the developer's responsibility to implement the singleton class and different methods could be used (such as "getInstance" "Instance" "returnInstance") to create/get the object.

Test

We create class "People" to test the singleton class "Earth". In Java, "People" class has "pollute" method, which accepts Earth object as parameter. The parameter type does not matter in Ruby because of its duck-typing. The test goes through the following steps:

  1. create earth1 and earth2 using Earth class's object creation mechanism
  2. print earth1 and earth2's state (currentCondition) before invoking "People"'s "pollute" method
  3. invoke "People"'s "pollute" method on earth1
  4. print earth1 and earth2's state (currentCondition)

Ruby Test Code

class People
 def pollute(a)  # pollute an earth object
  a.currentCondition="i am old and polluted"
 end

 def test
  p=People.new
  earth1=Earth.instance
  earth2=Earth.instance

  earth1.currentCondition="I am young and clean"
  puts "Earth1 says: " + earth1.currentCondition
  puts "Earth2 says: " + earth2.currentCondition
 
  # pollute earth1
  p.pollute(earth1)
  puts "After people pollute earth1"

  puts "Earth1 says: " + earth1.currentCondition
  puts "Earth2 says: " + earth2.currentCondition
 end
end

p=People.new
p.test

Java Test Code


public class People {
	public void pollute(Earth earth){
		earth.getEarth().setCurrentCondition("I am dirty and polluted");
	}
	public static void main(String args[]){
		People p=new People();
		Earth earth1= Earth.getEarth();
		Earth earth2= Earth.getEarth();	
		System.out.println("earth1 says: " +earth1.getCurrentCondition());
		System.out.println("earth2 says: " +earth2.getCurrentCondition());	
		p.pollute(earth1);
		System.out.println("After people pollute earth1");
		System.out.println("earth1 says: " +earth1.getCurrentCondition());
		System.out.println("earth2 says: " +earth2.getCurrentCondition());
		
	}
}

Test Result

Both the java code and the ruby code will produce the following output


 earth1 says: I was beautiful and clean
 earth2 says: I was beautiful and clean
 After people pollute earth1
 earth1 says: I am dirty and polluted
 earth2 says: I am dirty and polluted

Before invoking People's pollute method, earth1 and earth2 are "beautiful and clean", and after invoking the method on earth1, earth 1 and earth2 both change to "dirty and polluted". This illustrates actually only one Earth object. "We have only one earth"


References

  1. Programming Ruby: The programmatic programmer’s guide
  2. Head First Design Patterns

External Links

  1. Ruby standard library documentation
  2. Design Patterns - Wikipedia
  3. Patterns in Ruby: Singleton Pattern