Skip navigation

Part1 continued…..
Composite Pattern

Wiki Link. Use this in cases where your DSL seems to have a hierarchy. The hierarchy can be established  by data/logic i.e Tasks & SubTasks, Parts & SubParts.

class Part
  def initialize name
    @name = name
  end
  def weight
    0
  end
end

class Hand < Part
  def initialize
    super("Hand")
    @children = []
    5.times {add_child Finger.new}
  end

  def weight #component object
    weight  = 5
    @children.each { |c| weight += c.weight }
    weight
  end

  def add_child child
    @children << child
  end
end

class Finger < Part
  def initialize
    super("Finger")
  end

  def weight #Leaf object
    1
  end
end
hand = Hand.new
puts hand.weight #7

Note here that the complex weight methods have been implemented in the component class and not the leaf class.

Iterator

Composite Objects often are composed of lists of elements that are treated alike. This is particularly simple to accomplish in a duck typed language like Ruby. There is often a need to access individual items in the list. That really is the problem that iterators solve. For the Java folks java.util.iterator & java.util.Enumeration interfaces should strike a Bell. Typical use-case (Java Code):

ArrayList list = new ArrayList();  //Composite Object
list.add("java");
list.add("c++");
list.add("ruby");
for(Iterator i = list.iterator(); i.hasNext();)
{
  System.out.println("Language:" + i.next());
}

Although these are inherently a part of the code that you may write everyday, it pays to have an understanding of the problem that iterators essentially solve. There are essentially External Iterators. External since they are external to the Composite Object that they iterate.

Ruby on the other hand has internal iterators. Here is what is internal about them.

list = ["java", "c++", "ruby"]
list.each do |language|
  puts "Language: #{language}"
end

The difference here clearly being that the logic that you wish to apply in an iterative way is passed as a code bock to the composite object. Its clear from this example that internal iteratirs are an inherent part of languages that support closures. In this case the method each takes the code block to be applied iteratively.
Here is a nice article that explains the pros and cons of using different types of iterators.

Command

Wiki Link. Clearly, the closures in Ruby are bound to have an influence on the command patterns. As explained in the Composite pattern above, we can maintain commands as a bunch of proc objects. This example however is meant to demonstrate cases where there is a need to remember states. Hence the more conventional approach to solving command problems.


class Command
  def initialize(description, proc1, proc2)
    @description = description
    @function =  proc1
    @inverse = proc2
  end

  def execute
    @function.call unless @function.nil?
  end

  def unexecute
    @inverse.call unless @inverse.nil?
  end
end
class CreateFile < Command
  def initialize
    proc1 = Proc.new do
      puts "File Created"
    end
    proc2 = Proc.new do
      puts "File Destroyed"
    end
    super("creating new file", proc1, proc2)
  end
end

class CheckMemory < Command ##ireversible
def initialize
  proc1 = Proc.new do
    puts "Checking Memory..."
  end
  proc2 = Proc.new do
    puts "Mem Check need not be reversed"
  end
  super("Checking memory avalability", proc1, proc2)
  end
end

class Installer
  def initialize
    @commands = []
  end

  def add_command command
    @commands << command
  end

  def install
    @commands.each {|c| c.execute}
  end

  def uninstall
    @commands.reverse.each do |command|
      command.unexecute
    end
  end
end

installer = Installer.new
installer.add_command(CheckMemory.new)
installer.add_command(CreateFile.new)
installer.installinstaller.uninstall
Advertisements

One Comment

  1. Great post that really helped me understand the command pattern!

    Also, you are missing a line break in the last line of the command pattern example. “installer.installinstaller.uninstall” should be:
    installer.install
    installer.uninstall


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: