CSC/ECE 517 Fall 2009/wiki2 13 ncs: Difference between revisions
Tinydancer (talk | contribs) |
Tinydancer (talk | contribs) |
||
Line 20: | Line 20: | ||
Singleton | Example of Singleton class in Java | ||
<code> | <code> | ||
public class SingletonExample { | public class SingletonExample { | ||
// declare instance variable | // declare instance variable | ||
private static SingletonExample | private static SingletonExample singletonEx; | ||
// Make the constructor is private | // Make the constructor is private | ||
private SingletonExample () { | private SingletonExample() { | ||
} | } | ||
// make this thread safe use synchronize | // make this thread safe use synchronize | ||
synchronize public static SingletonExample getSingletonObject() { | synchronize public static SingletonExample getSingletonObject() { | ||
if ( | if (singletonEx == null) { | ||
singletonEx = new SingletonExample(); | |||
} | } | ||
return | return singletonEx; | ||
} | } | ||
} | } | ||
</code> | </code> | ||
Above is the skeleton of class that we need to write in Java for every singleton objects. Compare the Java code with the Ruby code below that was written using the singleton module. | |||
Example of Singleton class in Ruby (using singleton module) | |||
Singleton | |||
<code> | <code> | ||
require singleton | require singleton | ||
class SingletonExample | |||
include singleton | include singleton | ||
end | end | ||
</code> | </code> | ||
Ruby provides a more concise way of implementing the singleton pattern | Ruby provides a more concise way of implementing the singleton pattern by automatically providing all the functionality that we need to write manually in Java. By writing "include singleton" in Ruby, we prevent ourselves from having to repeat writing the same code for each class that we wish to make singleton. | ||
==Factory Pattern== | ==Factory Pattern== |
Revision as of 22:28, 9 October 2009
Introduction
Ruby offers more concise implementations of certain design patterns than Java does. We will look at some design patterns and compare the implementation in Ruby vs Java with the goal to answer the following:
- Is this typical of dynamic object-oriented languages?
- Are there design patterns that any dynamically typed language can realize better than a statically typed language?
- Are there instances when a different pattern should be used in a dynamic language than a static language?
Design Patterns in JAVA vs Ruby
Singleton Pattern
Singleton pattern is used to restrict the instantiation of the class to a single object.
The implementation of the pattern involves:
- making the constructor private
- declare a instance variable
- implement a getInstance method and make the it thread safe.
Example of Singleton class in Java
public class SingletonExample {
// declare instance variable
private static SingletonExample singletonEx;
// Make the constructor is private
private SingletonExample() {
}
// make this thread safe use synchronize
synchronize public static SingletonExample getSingletonObject() {
if (singletonEx == null) {
singletonEx = new SingletonExample();
}
return singletonEx;
}
}
Above is the skeleton of class that we need to write in Java for every singleton objects. Compare the Java code with the Ruby code below that was written using the singleton module.
Example of Singleton class in Ruby (using singleton module)
require singleton
class SingletonExample
include singleton
end
Ruby provides a more concise way of implementing the singleton pattern by automatically providing all the functionality that we need to write manually in Java. By writing "include singleton" in Ruby, we prevent ourselves from having to repeat writing the same code for each class that we wish to make singleton.
Factory Pattern
Isolate the code to create an object from the concrete implementation of the class.
In JAVA we typically do something like
interface IObjectFactory {
IGear createObject();
}
class ConcreteObjectFactory implements IObjectFactory{
IObject createObject() {
if ( some condition )
return new XObject();
else
return new YObject();
}
class ObjectUser {
public void doSomething(IObjectFactory factory ) {
IObject my_Object = factory.createObject();
}
}
We can technically do the exact same thing in Ruby however Ruby being a dynamic language there are no special classes or class methods in Ruby. Ruby allows us to rename our factory method to be called new.
class ObjectFactory
def new()
if ( ... some condition )
return XObject.new()
else
return YObject().new()
end
end
Our client class now becomes:
class ObjectUser
def doSomething(factory )
...
my_object = factory.new()
...
end
end
Ruby lets us redefine the new method and this allows us to implement the Factory pattern with a class that looks very much like an ordinary class. The client does not need to know about the special createObject methods.
Iterators
Iterators are design patterns used to access the elements of an aggregate object sequentially without exposing its underlying representation. To use iterators we need
- An iterator declared and initialized to point to the collection
- Write a loop and use the iterator to get the value of the next sequential objec tin the collection.
In JAVA we will need to know the type of objects in the collection and cast the objects to the right type to use them whereas in Ruby iterators are built right in. Here are some examples that show the ease with which we can use iterators in Ruby
a = [ 10, 20, 30, 40 ]
a.each { |element| print "The element is #{element}\n" }
Thread.list.each { |t| print "Thread: #{t}\n" }
ObjectSpace.each_object { |o| print "Object: #{o}\n" }
open("data.txt").each_line { |line| print "The line is #{line}\n" }
Conclusion
Design patterns are concepts that are equally applicable to solve problems regardless of the language we use to implement the solution. So I cannot think of a case where a specific apttern will be more useful or pertinent to be used in a dynamic language than a static language. However given the features of dynamic languages like Ruby that support metaprogramming and reflection via Modules and Mixins and support extending/reopening classes and redfining methods at run time definitely make it easier to implement patterns with fewer lines of code. Ruby lets us hide the details of implementations of design patterns much more effectively. You can make a class a singleton with a simple "include Singleton" statement. You can make factories that look exactly like ordinary classes. These features in Ruby do make implementing design patterns very easy and let a programmer focus on soving the problem at hand rather than spending time implementing the design patterns.