Delegando métodos em Ruby

Dicas - 15/Jul/2019 - por Henrique Morato

Muitas vezes enquanto estamos programando (tomara que todo o tempo), abusamos de composição, encapsulamento e injeção de dependências para facilitar a construção das classes. Constantemente, usamos outros objetos e queremos simplificar as classes ao máximo, fazendo com que elas respondam somente o necessário. Para descomplicar nossas classes podemos delegar métodos para objetos de outras classes. Em Ruby existem muitas formas de fazer isso – talvez mais do que deveria –, mas vamos ver as duas mais comuns.

Tome como exemplo o código abaixo:

class ContaCorrente
  attr_reader :numero, :cliente

  def initialize(numero, nome)
    @numero = numero
    @cliente = Cliente.new(nome) # Exemplo de composição
  end
end

class Cliente
  attr_reader :nome

  def initialize(nome)
    @nome = nome
  end
end

ContaCorrente tem um Cliente e o nome daquele cliente parece importante o suficiente para simplificarmos essa chamada na classe ContaCorrente.

Uma forma simples de fazer isso é chamar o método do outro objeto:

class ContaCorrente
  attr_reader :numero, :cliente

  def initialize(numero, nome)
    @numero = numero
    @cliente = Cliente.new(nome)
  end

  def nome
    cliente.nome
  end
end

No entanto, isso significa um método a mais, o que aumenta nossa classe. O Ruby implementa um módulo chamado Forwardable que permite delegar métodos específicos para outros objetos, usando o método def_delegator que é bastante direto. Nele passamos o objeto que será acessado e o método que será enviado: def_delegator objeto, :metodo

Implementando esse módulo, nossa classe pode ficar da seguinte forma:

require 'forwardable'

class ContaCorrente
  extend Forwardable
  attr_reader :numero

  def_delegator :@cliente, :nome

  def initialize(numero, nome)
    @numero = numero
    @cliente = Cliente.new(nome)
  end
end

Caso queira continuar o estudo sobre o assunto, existem outras alternativas e mais opções de executar a mesma ação, como usar def_delegators, alias para métodos e delegators em Rails, entre outras.