CSC/ECE 517 Fall 2009/wiki2 11 zv: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
Line 99: Line 99:


   public class FactoryFmProto {
   public class FactoryFmProto {
   static class Expression {
   static class Expression {
   protected String str;
   protected String str;
Line 106: Line 105:
   public String    toString()  { return str; }
   public String    toString()  { return str; }
   }
   }
   static abstract class Factory {
   static abstract class Factory {
   protected Expression prototype = null;
   protected Expression prototype = null;
Line 113: Line 111:
   public abstract Expression makeGrade();
   public abstract Expression makeGrade();
   }
   }
   static class PCFactory extends Factory {
   static class PCFactory extends Factory {
   public PCFactory() { prototype = new PCPhrase(); }
   public PCFactory() { prototype = new PCPhrase(); }
Line 128: Line 125:
       return new Expression( "\"take test, deal with the results\"" ); }
       return new Expression( "\"take test, deal with the results\"" ); }
   }
   }
   public static void main( String[] args ) {
   public static void main( String[] args ) {
   Factory factory;
   Factory factory;

Revision as of 18:32, 8 October 2009

Overview

Before starting off with design patterns for Ruby we need to define what a design pattern is, Design patterns can be described as "a general reusable solution to a commonly occurring problem in software design." [1] The idea of design patterns is to not to reinvent the wheel but to solve the current problems by using solutions that have worked in the past. A design pattern names, abstracts, and identifies the key aspects of a common design structure that make it useful for creating a reusable object-oriented design. It helps to identify the classes and instances and the way they collaborate with each other to form a solution to a problem. Design patterns c an be classified into 3 parts Creational, Structural, Behavioral (See if we can give links for these.)

Factory

Factories The factory design pattern is an object oriented design pattern. It is a creational design pattern and deals with the issues faced in creating objects. The main goal of this implementation is to isolate teh code that creates the class form the concete implementation of that class. Ruby example for the same is given below.


Factory Example in Ruby

   class GearFactory
     def new() 
       if ( ... some condition )
          return Sprocket.new()
       else
          return Cog().new()
       end
     end
   end

Our client class now becomes:

   class GearUser 
     def doSomething(factory )
       ...
     my_gear = factory.new()
       ...
     end
   end

The above code does not have to distinguish between a factory and an ordinary class. We can call the class using the followijng code.

   client.doSomething(GearFactory.new)          #Use the factory
   client.doSomething(Cog)                      #Use the Cog class
   client.doSomething(Sprocket)                 #Use the Sprocket class

Factory Example in Java

In java the Factory implementation is done using interfaces. Declaring them as interfaces helps to maintain a general overview and not depending on the type of factory object that needs to be used. All of these can be placed in a huge factory in a client application. A well known example for Java Factory is the UI toolkits that are designed to run on different windowing systems.

   interface ScrollBar { ... }
   interface MenuBar   { ... }
   ...

And associated classes implementing them on different windowing systems:

   class MotifScrollBar implements ScrollBar { ... }
   class Win95ScrollBar implements ScrollBar { ... }
   ...

And a factory interface that also doesn't commit to representation:

   interface Factory {
     public abstract ScrollBar newScrollBar();
     public abstract MenuBar   newMenuBar();
     ... 
   }

But implementation classes that do:

   class MotifFactory implements Factory {
     public ScrollBar newScrollBar() { return new MotifScrollBar(...); }
     ...
   }

Abstract Factory Pattern

What is Abstract Factory Pattern?

Abstract Factory Design Pattern encapsulates a group of objects that have common theme. It implements a generic interface to create these objects that are part of the theme. It does not care about the details of the implementation of these objects. The Abstract Factory pattern, a class delegates the responsibility of object instantiation to another object via composition. It is a type of Creational pattern [2] “Provide an interface for creating families of related or dependent objects without specifying their concrete classes” [3]

Implementation in Ruby

Ruby automatically implements the Abstract Factory pattern as Class Objects. All Class objects have the same interface: the new method of each class object creates new instances of the class. Thus the code can pass references to class objects around and they can be used to call new method without knowing the exact type of object that the class creates.

   Class Foo; end
   Class Bar, end


Here is the use of Abstract Factory Pattern

   def create_something(factory)

new_object = factory.new puts "created a new #{new_object.class} with a factory"

   end

Here we select a factory to use

   Create_something(Foo)
   Create_something(Bar)

Output of the code:
Created a Foo with a factory
Created a Bar with a factory

The create_something method is creating objects through an abstract interface. It does not have details about implementation used to create these objects. Thus the use of create_something() is used to shield the rest of the code from that knowledge.

Implementation in Java

In Java, implementing Abstract Factory design pattern we need to create a class which has method who defers creation of product objects to its concrete class. This class then needs to be ”extended” by the client class which uses only these interfaces to create objects of concrete class [4]. In Java, Abstract Factory defines a different method for the creation of each product it can produce. The following example shows an implementation of Abstract Factory design pattern in Java.


  public class FactoryFmProto {
 static class Expression {
  protected String str;
  public Expression( String s ) { str = s; }
  public Expression cloan()     { return null; }
  public String     toString()  { return str; }
 }
 static abstract class Factory {
  protected Expression prototype = null;
  public Expression makePhrase() { return prototype.cloan(); }
  public abstract Expression makeCompromise();
  public abstract Expression makeGrade();
 }
 static class PCFactory extends Factory {
  public PCFactory() { prototype = new PCPhrase(); }
  public Expression makeCompromise() {
     return new Expression( "\"do it your way, any way, or no way\"" ); }
  public Expression makeGrade() {
     return new Expression( "\"you pass, self-esteem intact\"" ); }
 }
  static class NotPCFactory extends Factory {
  public NotPCFactory() { prototype = new NotPCPhrase(); }
  public Expression makeCompromise() {
     return new Expression( "\"my way, or the highway\"" ); }
  public Expression makeGrade() {
     return new Expression( "\"take test, deal with the results\"" ); }
 }
  public static void main( String[] args ) {
  Factory factory;
  if (args.length > 0) factory = new PCFactory();
  else                 factory = new NotPCFactory();
  for (int i=0; i < 3; i++) System.out.print( factory.makePhrase() + "  " );
  System.out.println();
  System.out.println( factory.makeCompromise() );
  System.out.println( factory.makeGrade() );
 }
 }

Comparison of Implementations

Basically, Java and Ruby, both can implement Abstract Factory design pattern. But the more important point is the simplicity by which they can apply it. Ruby automatically implements the Abstract Factory pattern as Class Objects. But Java needs helps of interfaces and classes to do so. Thus Java implementation needs a well defined interface to do so but in Ruby it is directly implemented because of private class object property.

Similarly, C# demonstrates the Abstract Factory pattern by creating parallel hierarchies of objects. Object creation has been abstracted and there is no need for hard-coded class names in the client code. This property helps C# to have better implementation than Java. In .NET, there are built in features such as, generics, reflection, object initializers, automatic properties, etc for implementation [5].

Iterator Design Pattern

An Iterator object encapsulates the internal structure of how the iteration occurs. It is a type of Behavioral design pattern. [6]. “Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.” [7]

Ruby implements iterators with blocks and the ‘each’ method, and with ‘for..in’ statements. For example consider the following example;

   def print_element(container)
   	Container.each {|o| puts o.inspect }
   end
   list = [1,2,2,3]
   hash = {“a”=>1, “b”=>2,”c”=>3, “d”=>4 }
   print_elements list
   print_elements hash

The output of the code is,

   1
   2
   3
   4
   [“a”,1]
   [“b”,2]
   [“c”,3]
   [“d”,4]

In Java implementing Iterator design pattern would again involve having an interface for accessing and traversing the elements which is further implemented by the concrete class. Thus a class who needs to access the list will need to call the interface class. [8] Thus Ruby helps in implementing this design pattern easily by providing functions like “each” which does the handling of the concrete class implementation.

Decorator Pattern

It is used to increase the functionality of the existing object dynamically. It adds the behavior at runtime. The below code is an example of decorators where we just create a place holder and we can use this function to perform different functions depending on the parameters supplied to it. The need for this kind of pattern is so as to increase the functionality of a particular class.

Decorator Example in Ruby

In this example we talk about how a coffee class can have many addtions to it like coffee with cream, sprinkles, milk etc and creating a class for each of them will not be the correct solution.In this example the cost can be calculated according to what is sent to it.Cost of the coffee is 2 and the cost of White coffee (coffee + milk) = 2.4. So what happens when we execute the Sprinkles.new(Whip.new(Milk.new(Coffee.new))).cost we get the result as 2.9 as the cost of the coffee is 2, the decorator object (now only coffee) is sent to the Milk and it becomes 2.4, which now is then sent to the Whip which is going to be 2.4 + 02 = 2.6 and finally to Sprinkles which becomes 2.6 + 0.3 = 2.9.

   module Decorator
     def initialize(decorated)
       @decorated = decorated
     end
   def method_missing(method, *args)
       args.empty? ? @decorated.send(method) : @decorated.send(method, args)
   end
  end
   class Whip
     include Decorator
     def cost 
       @decorated.cost + 0.2
     end
   end
   class Sprinkles
     include Decorator
     def cost
       @decorated.cost + 0.3
     end
   end
   Whip.new(Coffee.new).cost
   #=> 2.2
   Sprinkles.new(Whip.new(Milk.new(Coffee.new))).cost 
   #=> 2.9

Decorator Example in Java

The components for this example are described below

  • Component: Defines the interface for objects that can have responsibilities added to them dynamically.
  • ConcreteComponent: Defines an object to which additional responsibilities can be attached.
  • Decorator: maintains a reference to a Component object and defines an interface that conforms to Component's interface.
  • ConcreteDecorator: adds responsibilities to the component.


   package decorator;
   public interface IComponent {
   public void doStuff();
   }

The Concrete component

   package decorator;
   public class Component implements IComponent{
   public void doStuff() {
   System.out.println("Do Suff");
   }
   }

The Decorator

   package decorator;
   public interface Decorator extends IComponent {
   public void addedBehavior();
   }

The Concrete Decorator (Extends IComponent)

   package decorator;
   public class ConcreteDecorator implements Decorator {
   IComponent component;
   public ConcreteDecorator(IComponent component) {
   super();
   this.component = component;
   }
   public void addedBehavior() {
   System.out.println("Decorator does some stuff too");
   }
   public void doStuff() {
   component.doStuff();
   addedBehavior();
   }
  }

The Client

   import decorator.*;
   public class Client {
   public static void main(String[] args) {
   IComponent comp = new Component();
   Decorator decorator = new ConcreteDecorator(comp);
   decorator.doStuff();
   }
   }