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.