#2 Metaprogramação: Definindo métodos

Posted on February 10, 2010

8


Ruby não tem um compilador para analisar as chamadas aos métodos.
Compiladores podem verificar por erros antes do código rodar, porém
essa proteção tem um custo alto, onde linguagens estáticas forçam o programador a escrever códigos repetitivos, como os os getters e setters do Java.

Vamos analizar um problema e refatorá-lo usando um pouco de metaprogramação.

Temos um banco de dados com objetos referentes a um Computador, como mouse, teclado e cpu. Um código legado busca informações sobre determinado Computador através de uma classe chamada BancoDeDados:

Argh..! Pra cada informação um método diferente. Muita repetição.
Vamos melhorar esse código.

Metaprogramação

Uma primeira idéia seria criar uma classe chamada Computador, que poderia receber os dados do banco e o id do computador procurado. Além disso poderia ser melhorada a questão dos métodos. Poderíamos ter métodos mais interessantes e expressivos, como mouse e cpu, retornando a informação.


É bem mais interessante trabalhar com a classe Computador. Porém..da-lhe repetição novamente. Pra criar informações de teclado seria um método praticamente copiado dos anteriores.

Dynamic Methods

Invocar um método significa enviar uma mensagem a um objeto. Isso pode ser feito da maneira tradicional, ou seja, “objeto ponto método”, ou através do método send.

O primeiro argumento do método send é o nome do método a ser invocado.

E por que você usaria essa notação ? Qual a vantagem em chamar um método através do send ?

Esse é um dos pontos mais interessantes da linguagem, pois com o método send os nomes dos métodos não são nada mais que argumentos. Strings!. Ou seja, você pode decidir a qualquer momento qual método vai chamar. Essa técnica é conhecida como Dynamic Dispatch.

Você pode ainda definir um método dinamicamente com o método define_method.

Refatorando

Ok. E onde usar isso tudo ?

Refatorando a classe Computador para invocar métodos através do método send conseguimos retirar muita duplicação:

Agora uma chamada ao método cpu delega para componente que utiliza o parametro string para invocar o método!
Muito melhor. Mas… ainda existe duplicação, cada componente tem um método de delegação, por que não utilizar o define_method visto anteriormente ?

Ha! Tomara que nesse momento você esteja lembrando de uma série de métodos encontrados em gems ou mesmo no Rails…😀
(Você ainda pode retirar essa última duplicação na definição dos componentes, pense um pouco)

Continua
Próximo post – method_missing()