XP on Rails Extreme Programming Blog

30Jul/100

Design Patterns in Ruby: Chain of Responsibility

ORIGINAL POST

Today’s post discusses the first of the behavioral pattern shown by the GoF, the chain of responsibility.

This pattern expects a series of commands to be executed and a set of objects capable to handle them.
Each of these “handler” objects can send the command to the next handler in the chain if it is not able to carry it out.
A mechanism also exists for adding new handler objects to the end of this chain.

To show this pattern, we take as example a real situation very familiar to web developers.

Suppose that the manager must deliver a new web project.

To realize the entire project should be conducted several heterogeneous activities such as design the user interface, develop the application, write the user manual, deploy the application.

The manager doesn’t have all required skills but he can rely on a pool of developers.

When the activity reaches a developer, this can solve it or, if he is unable to, send it to a colleague.
In this way a chain of responsibility is formed, where each actor specializes in solving only certain types of requests.

Let’s see how to carry out this scenario in Ruby.

Is therefore necessary that every element in the chain has the ability to “forward” the request to the next if he is not able to manage it.

So we create a module that defines this common logic and removes code duplication.

#models.rb
module Chainable

  def next_in_chain(link)
    @next = link
  end

  def method_missing(method, *args, &block)
    if @next == nil
      puts "This request cannot be handled!"
      return
    end
    @next.__send__(method, *args, &block)
  end
end

As you can see, the next_in_chain method provides the next element in the chain.
To meet demands that can not be managed, I’ve used the method_missing “pattern” : when the request can not be managed by the actor (e.g. the invoked method is not defined in the class), it will be forwarded to the next.

Now define the players of our example:

#models.rb
class WebManager
  include Chainable

  def initialize(link = nil)
    next_in_chain(link)
  end
 
  def deliver_application
    design_interface
    build_application
    write_documentation
    deploy_application
    puts "#{self.class.to_s}: Application delivered"
  end

end

class WebDeveloper
  include Chainable

  def initialize(link = nil)
    next_in_chain(link)
  end

  def build_application
    puts "#{self.class.to_s}: I'm building the application"
  end

  def deploy_application
    puts "#{self.class.to_s}: I'm deploying the application"
  end

end

class WebDesigner
  include Chainable

  def initialize(link = nil)
    next_in_chain(link)
  end

  def design_interface
    puts "#{self.class.to_s}: I'm designing the interface"
  end

end

class TechnicalWriter
  include Chainable

  def initialize(link = nil)
    next_in_chain(link)
  end

  def write_documentation
    puts "#{self.class.to_s}: I'm writing the documentation"
  end

end

At this point we simulate our chain by running the following code:

#main.rb
require 'models.rb'

provider = WebManager.new(WebDeveloper.new(WebDesigner.new(TechnicalWriter.new)))
provider.deliver_application
provider.make_support

and the output will be:

WebDesigner: I’m designing the interface
WebDeveloper: I’m building the application
TechnicalWriter: I’m writing documentation
WebDeveloper: I’m deploying the application
WebManager: Application delivered
This request cannot be handled!

In conclusion, the use of this pattern is useful when we deal with heterogeneous requests and we want to make sure that these are best handled by a specific handler.
It can also be used when we run commands in sequence, where each element forwards the coming command to the next handler.

An alternative to this pattern could be a decorator, able to add capacity to a specific handler. In this case a single handler will completely manage all requests.

In these first three articles of the series we have analyzed the first pattern shown by the GoF for each category.

In the coming articles I will no more follow the order set by the GoF but I’ll analyze the most useful patterns to address the most common needs.

Source code here

Previous posts from this series:
Design Patterns in Ruby: Introduction
Design Patterns in Ruby: Abstract Factory
Design Patterns in Ruby: Adapter

Filed under: Development No Comments
7Jul/101

Design Patterns in Ruby: Adapter

ORIGINAL POST

This second post of the series leaves for a moment the creational patterns and speaks about one of the most important structural pattern: the Adapter.

The purpose of an adapter is “to convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.”

Suppose therefore to have two classes, PalGame and NtscGame, that extend a superclass Game. These subclasses respectively expose two methods: play and run.

#models.rb
class Game
  attr_accessor :title
  def initialize(title)
    @title = title
  end
end

class PalGame < Game
  def play
    puts "I am the Pal version of #{@title} and I am running!"  
  end
end

class NtscGame < Game  
  def run
    puts "I am the NTSC version of #{@title} and I am running!"  
  end
end

We then subclass a Console class with PalConsole and NtscConsole. These two classes are expected to talk with, respectively, games of kind PalGame and NtscGame.

#models.rb
class Console
end

class PalConsole < Console
  def play_game(game)
    game.play  
  end
end

class NtscConsole < Console
  def run_game(game)
    game.run  
  end
end

How can see, the method play_game of a PalConsole will call the play method of the game, the NtscConsole instead will invoke the run method.

Our goal is to let a PalConsole to run games of kind NtscGame.

Below we’ll follow the line traced by the GoF and we’ll build an Adapter class that provides the play method needed by the PalConsole’s interface:

#adapters.rb
class NtscToPalAdatper
  attr_accessor :game
  def initialize(game)
    @game = game
  end
 
  def play
    @game.run  
  end  
end

As you can see, the adapter exposes a simple play method that calls the run method of the NTSCGame.

The following code:

#main.rb
require 'models.rb'
require 'adapters.rb'

console = PalConsole.new

final_fantasy = NtscGame.new("Final Fantasy")

adapter = NtscToPalAdatper.new(final_fantasy)

console.play_game(adapter)

will produce this output:
I am the NTSC version of Final Fantasy and I am running!

We see at this point some alternatives to further exploit the potential of Ruby.

One possibility is to take advantage of the Ruby’s “open classes”. The language makes possible to add methods to an already loaded class in this way:

#main2.rb
require 'models.rb'

console = PalConsole.new

class NtscGame < Game  
  def play
    run
  end
 
  # alternatively for this simple example we can define an alias:
  # alias play run
end

final_fantasy = NtscGame.new("Final Fantasy")

double_dragon = NtscGame.new("Double Dragon")

console.play_game(final_fantasy)

console.play_game(double_dragon)

As we can see, we’ve added at runtime the method play for a NtscGame game.

The above code produces the following output:
I am the NTSC version of Final Fantasy and I am running!
I am the NTSC version of Double Dragon and I am running!

Note however that with this solution we added the play method to the entire class NtscGame. All instances that are created will be equipped with the play method.
This type of action is very risky because it could not guarantee compatibility with other libraries, for example because of name clash.

Another alternative would be to use the “singleton classes”.
Ruby makes it possible to change a single instance of a class, by creating an anonymous class as its superclass that implements the new defined method.

There are several possibilities to implement these singleton classes. Let’s see in the following snippet some implementations.

#main3.rb
require 'models.rb'

console = PalConsole.new

#1 - creating a singleton class
final_fantasy = NtscGame.new("Final Fantasy")

def final_fantasy.play
  run  
end

console.play_game(final_fantasy)


#2 - adding methods opening the singleton class directly
winning_eleven = NtscGame.new("Winning Eleven")

class << winning_eleven
  def play
    run
  end
end

console.play_game(winning_eleven)


#3 - adding methods from a module
thunderforce = NtscGame.new("Thunderforce")

module Foo
  def play
    run
  end
end

thunderforce.extend(Foo)

console.play_game(thunderforce)


#4 - adding methods inside an instance_eval call
dragons_lair = NtscGame.new("Dragons Lair")

dragons_lair.instance_eval <<EOT
  def play
    run
  end
EOT

console.play_game(dragons_lair)

All implementations will provide the same type of output:
I am the NTSC version of Final Fantasy and I am running!
I am the NTSC version of Winning Eleven and I am running!
I am the NTSC version of Thunderforce and I am running!
I am the NTSC version of Dragons Lair and I am running!

In this post we have therefore seen the usefulness of this design patterns and how Ruby allows the developer to “leave” the classic implementation suggested in order to better take advantage of the potentiality of the language.

source code here

Previous posts from this series:
Design Patterns in Ruby: Introduction
Design Patterns in Ruby: Abstract Factory