Subsecciones


Delegación

La delegación es un patrón de diseño que consiste en que ciertas tareas, en vez de ser realizadas por el objeto son delegadas en ciertos objetos asistentes.

Delegación usando DelegateClass

Una forma de delegar en Ruby consiste en que la clase sea una subclase de DelegateClass, a la que se le pasa el nombre de la clase en la que se delega como parámetro (Flintstone en el ejemplo).
class Fred < DelegateClass(Flintstone)
  def initialize
    # ...
    super(Flintstone.new(...))
  end
  # ...
 end
Luego, en el initialize llamamos al de la superclase, pasandole como argumento el objeto en el que se delega.

Por ejemplo, podríamos reescribir la práctica de los conjuntos en la sección 14.6 delegando en la clase Array los métodos length e include? (Puede encontar este fichero en https://gist.github.com/crguezl/):

~/rubytesting/sets$ cat -n setsdelegate.rb 
     1  require 'delegate'
     2  class Set2 < DelegateClass(Array)
     3  
     4    attr_accessor :sep
     5    attr_reader :a
     6    protected :a
     7  
     8    def initialize(a)
     9      @sep = ', '
    10      @a = a.uniq.sort
    11      super(@a)
    12    end
    13  
    14    def to_s
    15      @a.join(@sep)
    16    end
    17  
    18    # delegated
    19    #def length 
    20    #  @a.length
    21    #end
    22  
    23    alias cardinal length
    24  
    25    # delegated
    26    #def include?(x)
    27    #  @a.include? x
    28    #end
    29  
    30  end
    31  
    32  if __FILE__  == $0
    33    x = Set2.new [1, 2, 3, 3, 4]
    34    puts "x = #{x}"
    35    puts "x.length = #{x.length}"              # x.length = 4 
    36    puts "x.cardinal = #{x.cardinal}"          # x.cardinal = 4
    37  
    38    puts "x includes 2 = #{x.include? 2}"      # x includes 2 = true
    39    puts "x includes 8 = #{x.include? 8}"      # x includes 8 = false
    40  end
En realidad DelegateClass(Array) es una llamada al método DelegateClass del package delegate.

~/rubytesting/sets$ ruby setsdelegate.rb 
x = 1, 2, 3, 4
x.length = 4
x.cardinal = 4
x includes 2 = true
x includes 8 = false

Otra forma de delegar es usar el método delegate de Rails. Podemos instalar rails usando gem:

~$ sudo gem install rails
Password:
Successfully installed rails-3.1.1
1 gem installed
Installing ri documentation for rails-3.1.1...
file 'lib' not found
Installing RDoc documentation for rails-3.1.1...
file 'lib' not found
~$

Delegación usando Rails

El método delegate recibe la lista de nombres de los métodos (especificados como símbolos o strings) a delegar y el nombre del objeto atributo en el que se delega, especificado mediante la clave :to. Véase https://gist.github.com/crguezl/.

~/rubytesting/TheRubyProgrammingLanguage/chapter8ReflectionandMetaprogramming$ cat -n delegation2.rb 
   1  require "rails"
   2  module I
   3    def f
   4      puts "#{self.class}: doing f()"
   5    end
   6   
   7    def g
   8      puts "#{self.class}: doing g()"
   9    end
  10  end
  11   
  13  class A
  14    include I
  15  end
  16   
  18  class B
  19    include I
  20  end
  22   
  23  class C
  24    attr_accessor :i
  25    delegate :f, :g, :to => :i
  26   
  27    def initialize(klass = A)
  28      self.i = klass.new
  29    end
  30  end
  32   
  33  c = C.new
  34  c.f         # output: A: doing f()
  35  c.g         # output: A: doing g()
  36  c = C.new(B)
  37  c.f         # output: B: doing f()
  38  c.g         # output: B: doing g()

Véase

  1. Delegation patterns in Ruby. Reducing object bloat begins with doing less by Samuel Mullen

Casiano Rodriguez León 2015-01-07