Delegação em Ruby utilzando o módulo Forwardable
Criado em: 21/02/2013
Em Ruby temos o poder de fazer overloading de operadores, ou seja definirmos nossa própria implementação para os operadores.
Quando temos uma classe que é uma coleção é uma boa idéia, se fizer sentido, definirmos os operadores <<
, []
e []=
pois assim teremos uma interface igual a de um Enumerable.
Tecnicamente os operadores []
e []=
não são operadores e sim métodos, em que o Ruby aplica um açucar sintático assim quando fazemos foo[2]
estamos chamando o método []
em foo
, passando o parâmetro 2 e quando fazemos foo[2] = 4
estamos na realidade chamando o método []=
em foo
passando os parâmetros 2 e 4, por isso conseguimos fazer overloading destes métodos também.
Vamos a um exemplo:
criamos uma classe Basket
que é nossa cesta, seu papel é ser uma coleção de items, vamos vê-la em ação:
Como pode ver agora nossa classe se comporta como um Enumerable
no entanto se observar bem os métodos que implementamos, nada mais são do que delegar para os métodos do Enumerable
, vamos a uma implementação mais inteligente.
Utilizando o Forwardable
O Ruby possui o módulo Forwardable que nos permite delegar métodos específicos para um objeto.
Ou seja poderemos delegar os métodos de array, para o nosso próprio array @items
. Vamos ao código:
Ao utilizarmos a nossa nova classe Basket
obtemos o mesmo resultado da classe anterior:
Vamos agora entender o que aconteceu.
def_delegator
Primeiro utilizamos o def_delegator
que nos permite definir um delegator, para um único método do objeto e opcionalmente definir um nome diferente ao método. No nosso exemplo usamos o Basket#total_of_items
pois para a nossa interface faz mais sentido este nome do que apenas Basket#size
.
def_delegators
Como você já deve imaginar o def_delegators
nos permite definir diversos delegators, para diversos métodos do objeto, no entanto não é possível definir um nome diferente ao método. Utilizamos ele para criar os demais métodos <<
, []
e []=
.
Como pode ver o uso do Forwardable
fez nossa classe mais enxuta e não precisamos redefinir os métodos já existentes em nosso objeto. Lembrando que pode-se definir qualquer método de um dado objeto, cabe a você fazer as escolhas certas para manter uma interface clara.
Comentários
Comentários powered by Disqus