CSC/ECE 517 Fall 2007/wiki1b 7 as: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
mNo edit summary
Line 18: Line 18:


Both Java and Ruby are object oriented programming languages in which command pattern can be implemented by turning the request itself into an object. This object can be stored and passed around like other objects. The Receiver has the knowledge required to carry out the request. In Java the implementation is through ''interfaces'' and in Ruby the implementation is through ''mixins''. The difference in implementation of command patterns in Java and Ruby are brought out using a simple example that undos the concatination operation on strings. Because of concepts such as meta-programming, modules, mixins many of the design patterns have much simpler, cleaner implementations in Ruby.  
Both Java and Ruby are object oriented programming languages in which command pattern can be implemented by turning the request itself into an object. This object can be stored and passed around like other objects. The Receiver has the knowledge required to carry out the request. In Java the implementation is through ''interfaces'' and in Ruby the implementation is through ''mixins''. The difference in implementation of command patterns in Java and Ruby are brought out using a simple example that undos the concatination operation on strings. Because of concepts such as meta-programming, modules, mixins many of the design patterns have much simpler, cleaner implementations in Ruby.  
The following explanation from the webpage [http://www.javaworld.com/javaworld/jw-07-2006/jw-0717-ruby.html] captures the advantages of Ruby implementation of command patterns over Java in a succinct and clear manner.
"Execute() methods in the Command design pattern must return Object rather than a specific type in pre-Java 5 code, resulting in ClassCastExceptions. Likewise, when signatures change between compile-time and runtime, runtime Errors ensue. In practice, whether in Java or Ruby, such errors rarely cause severe field bugs. A strong unit test suite—which you need anyway!—generally catches them in time.
Ruby's dynamic typing does not mean weak typing—Ruby always requires you to pass objects of the correct type. Java, in fact, enforces types more weakly than Ruby. For example, Java evaluates "4" + 2 as "42", coercing the integer to a string, while Ruby throws a TypeError, telling you it "can't convert Fixnum into String." Likewise, Java, sacrificing correctness for speed, can silently overflow an integer operation, producing weirdness such as Integer.MAX_VALUE + 1, which equals Integer.MIN_VALUE, while Ruby simply expands integers as needed."


====Implementation in Java====
====Implementation in Java====
Line 159: Line 153:
>>no command done to undo
>>no command done to undo
</pre></code>
</pre></code>
====Advantages of Ruby over Java====
The following explanation from the webpage [http://www.javaworld.com/javaworld/jw-07-2006/jw-0717-ruby.html] captures the advantages of Ruby implementation of command patterns over Java in a succinct and clear manner.
"Execute() methods in the Command design pattern must return Object rather than a specific type in pre-Java 5 code, resulting in ClassCastExceptions. Likewise, when signatures change between compile-time and runtime, runtime Errors ensue. In practice, whether in Java or Ruby, such errors rarely cause severe field bugs. A strong unit test suite—which you need anyway!—generally catches them in time.
Ruby's dynamic typing does not mean weak typing—Ruby always requires you to pass objects of the correct type. Java, in fact, enforces types more weakly than Ruby. For example, Java evaluates "4" + 2 as "42", coercing the integer to a string, while Ruby throws a TypeError, telling you it "can't convert Fixnum into String." Likewise, Java, sacrificing correctness for speed, can silently overflow an integer operation, producing weirdness such as Integer.MAX_VALUE + 1, which equals Integer.MIN_VALUE, while Ruby simply expands integers as needed."
In our Ruby implementation, the command pattern for undo is coded as a module, what can be included for any class or just an object.  While in Java, its been implemented as an interface forcing it be implemented by every class that needs this functionality.  Also, implementing it as a separate module makes 'do' and 'undo' code to be written only once and any object/class can be extended easily.  While in Java, each class that implements this interface must have a separate definition for the code.  This has several disadvantages like increases code complexity, size and is generally confusing and tedious to trace or understand the code.


==References==
==References==

Revision as of 22:32, 8 October 2007

Command Patterns

Definition : Command Pattern is a Design Pattern that encapsulates invocation and allows code that causes actions to be initiated to be separated from code that performs those actions.

Why use Command Patterns?

A Command pattern is an object behavioral pattern that allows us to achieve complete decoupling between the sender and the receiver. (A sender is an object that invokes an operation, and a receiver is an object that receives the request to execute a certain operation. With decoupling, the sender has no knowledge of the Receiver's request.) The term request here refers to the command that is to be executed. The Command pattern also allows us to vary when and how a request is fulfilled. Therefore, a Command pattern provides us flexibility as well as extensibility.


Use of Command Patterns

  • Decouple the object that invokes the operation from the one that performs the action described earlier.
  • Assemble commands into a composite command.
  • Add new Commands, without having to change existing classes.


Implementation of Command Patterns in Java Vs Ruby

Both Java and Ruby are object oriented programming languages in which command pattern can be implemented by turning the request itself into an object. This object can be stored and passed around like other objects. The Receiver has the knowledge required to carry out the request. In Java the implementation is through interfaces and in Ruby the implementation is through mixins. The difference in implementation of command patterns in Java and Ruby are brought out using a simple example that undos the concatination operation on strings. Because of concepts such as meta-programming, modules, mixins many of the design patterns have much simpler, cleaner implementations in Ruby.

Implementation in Java

The key to implementing command patterns in Java are interfaces, which declare the executing operations. In its simplest form, this interface includes an abstract execute operation. Each concrete Command class specifies a receiver-action pair by storing the Receiver as an instance variable. It provides different implementations of the execute() method to invoke the request.

Example Code

import java.util.ArrayList;
interface CommandPattern {
	void doCommand();
	void undoCommand();
}

class NewString implements CommandPattern {
	
	private ArrayList<String> states = new ArrayList();
	private String s;
	
	public NewString (String args) {
		s = args;
	}
	
	public ArrayList<String> getStates() {
		return states;
	}

	public void setStates(ArrayList<String> states) {
		this.states = states;
	}
	
	public void concat(String args) {
		doCommand();
		s = s.concat(args);
	}
	
	public void doCommand() {
		states.add(this.s);
	}
	
	public void undoCommand() {
		if(states.size() > 0) {
			s = states.get(states.size()-1);
			states.remove(states.size()-1);
		}
		else
			System.out.println("no command done to undo");
	}

	public String getS() {
		return s;
	}

	public void setS(String s) {
		this.s = s;
	}
	
	public static void main(String[] args) {
	
		NewString s = new NewString("sample ");
		System.out.println(s.getS());
		s.concat("123");
		System.out.println(s.getS());
		s.undoCommand();
		System.out.println(s.getS());
		s.undoCommand();
		System.out.println(s.getS());
	}
}

Sample Output:

$ sample
$ sample123
$ sample
$ no command done to undo

Implementation in Ruby

The key to implementing command patterns in Java are mixins, which define the executing operations. In its simplest form, this mixin include the implementation of the execute operation. Each Command class that specifies a receiver-action pair by storing the Receiver as an instance includes the mixin and calls the execute operation of the mixin.

Example Code

$ irb
module CommandPattern  
  def undoCommand()    
    if(@states.length > 0)
        initialize(@states.pop())
    else
        puts "no command done to undo"
    end
  end
  
  def doCommand(object)
  
    if(@states == nil)
      @states = []
    end
    
    @states.push(object)
    puts "docommand #{object}" 
  end
end

class NewString < String 
  include CommandPattern
  attr_accessor :states
  def initialize(arg)
    super(arg)
  end
  def concat(arg)
    doCommand(to_s())
    super(arg)
    
  end
end

Sample Output:

>a = NewString.new("sample")
>puts a
>>sample
>a.concat("123")
>puts a
>>sample123
>a.undoCommand()
>puts a
>>sample
>a.undoCommand()
>>no command done to undo

Advantages of Ruby over Java

The following explanation from the webpage [1] captures the advantages of Ruby implementation of command patterns over Java in a succinct and clear manner.

"Execute() methods in the Command design pattern must return Object rather than a specific type in pre-Java 5 code, resulting in ClassCastExceptions. Likewise, when signatures change between compile-time and runtime, runtime Errors ensue. In practice, whether in Java or Ruby, such errors rarely cause severe field bugs. A strong unit test suite—which you need anyway!—generally catches them in time.

Ruby's dynamic typing does not mean weak typing—Ruby always requires you to pass objects of the correct type. Java, in fact, enforces types more weakly than Ruby. For example, Java evaluates "4" + 2 as "42", coercing the integer to a string, while Ruby throws a TypeError, telling you it "can't convert Fixnum into String." Likewise, Java, sacrificing correctness for speed, can silently overflow an integer operation, producing weirdness such as Integer.MAX_VALUE + 1, which equals Integer.MIN_VALUE, while Ruby simply expands integers as needed."

In our Ruby implementation, the command pattern for undo is coded as a module, what can be included for any class or just an object. While in Java, its been implemented as an interface forcing it be implemented by every class that needs this functionality. Also, implementing it as a separate module makes 'do' and 'undo' code to be written only once and any object/class can be extended easily. While in Java, each class that implements this interface must have a separate definition for the code. This has several disadvantages like increases code complexity, size and is generally confusing and tedious to trace or understand the code.

References

  • Wikipedia page, [2]
  • Javaworld, a pretty detailed discussion on pros and cons of using java and ruby for various purposes. [3]
  • How to implement Command Pattern in java [4]
  • Example of Undo Implementation [5]
  • A good explanation of Ruby functionalities [6]
  • For further reading [7]
  • A Good Books. Design patterns in java [8]

Contributors

  • Ashwin Veeravalli [9]
  • Satya N Viswanathan [10]