domingo, 8 de março de 2009

Ruby: getters e setters

Hoje vou falar um pouco a respeito de variáveis de instância em classes no Ruby e seus métodos de acesso.

No Ruby, diferentemente do Java, todas as variáveis de instância tem controle de acesso private, ou seja, só são acessíveis (escrita ou leitura) diretamente para os métodos dentro da própria classe.

Para explicar melhor o porque isso é uma boa característica da linguagem, vou falar a respeito de acoplamento entre classes.

Em orientação a objetos falamos que acoplamento entre classes é o nível em que uma classe tem acesso aos dados de outra. O ideal é que as classes tenham baixo acoplamento entre si, isso é, acessem as variáveis das outras classes apenas através dos métodos disponíveis por ela (encapsulamento).

Vou dar um exemplo de uma relação de classes com alto acoplamento (característica não recomendada) em Java:





Nesse exemplo temos a classe A e a classe B. A classe B contém um objeto do tipo A.

Note na linha 6 da classe B que ela acessa diretamente a variável de instância name da classe A, uma vez que ela tem nível de acesso public.

Esse tipo de relacionamento pode vir a trazer problemas futuramente, especialmente para a classe B, caso a classe A troque o nome da variável de instância name, ou algo do gênero.

O recomendado nesse caso seria que a variável name tivesse nível de acesso private e a classe disponibilizasse métodos para que classes externas acessem essa variável.

Como no exemplo abaixo:





Dessa vez a classe B utiliza o método setName da classe A para alterar a informação desejada. Dessa forma a classe A pode alterar sua lógica interna futuramente, sem precisar se preocupar com as classes que se relacionam com ela, portanto que ela mantenha os métodos getName e setName funcionando corretamente.

Isso é um exemplo de baixo acoplamento entre classes, e essa é a boa prática.

Como eu estava dizendo, no Ruby as variáveis de instância são sempre privates, o que nos força a trabalhar da forma certa, fornecendo métodos getters e setters para interação com outras classes.

Na verdade existem métodos como o instance_variable_get, que retorna o valor de uma variável de instância, mas métodos como esse só devem ser usados em caso de extrema necessidade. Para o nosso texto, vamos utilizar os métodos getters e setters.

Então toda vez que eu criar uma classe tenho que construir métodos getters e setters para cada uma das variáveis de instância que eu desejar deixar disponível para leitura ou escrita por outras classes?

Na teoria sim, mas o Ruby possui alguns métodos que nos ajudam bastante para esse tipo de tarefa, são eles : attr_accessor, attr_reader e attr_writer.

Por exemplo, vou criar uma classe User, dessa vez em Ruby, que possua as variáveis de instância name e age, as quais eu vou permitir que qualquer outra classe leia e altere seus valores (portanto vou criar métodos getters e setters).



Para acessar os dados das variáveis de instância de um objeto dessa classe seria dessa forma:



Por enquanto lembra um pouco o Java, certo?

Agora vamos usar uma técnica bem interessante. Vamos nomear os métodos getters com o mesmo nome da variável e os métodos setters com o nome seguido de um sinal de igual (=), veja o exemplo:



Agora podemos acessar os valores de um objeto dessa classe da seguinte forma:



Isso é possível graças há uma grande característica do Ruby chamada Syntactic Sugar, que torna possível a criação de códigos mais amigáveis. No caso do exemplo acima o Ruby nos permite adicionar um espaço antes e depois do sinal de igual e não usar parênteses para invocar o método.

Agora vamos falar sobre a parte interessante. Na verdade todo esse trabalho não precisa ser feito se eu for apenas criar métodos que permitam acesso ao conteúdo de uma variável.

Existe um método chamado attr_accessor que faz todo esse trabalho para nós (cria a variável de instância e os métodos getters e setters para ela).

Para isso basta eu chamar o método e passar como parâmetros o nome dos campos que eu desejo que sejam minhas variáveis de instância. No caso de nosso exemplo, ficaria da seguinte forma:



E poderíamos acessar os dados da mesma forma que no outro exemplo:



Como dito acima, o método attr_accessor cria métodos de acesso para leitura e escrita das variáveis de instância passadas a ele. Para os casos em que precisamos criar apenas os métodos de leitura ou escrita, usamos os métodos attr_reader e attr_writer, em seu lugar.

Bom pessoal, essa foi mais uma pequena contribuição no blog para o pessoal que deseja aprender mais sobre a linguagem Ruby, a qual eu recomendo e encorajo o aprendizado.

Para ler mais a respeito visitem a API do ruby e procurem pelos métodos attr_accessor, attr_reader, attr_writer e attr.

Gostaria de agradecer ao Fábio Kung que me tirou dúvidas a respeito desse post e está sempre me ajudando por e-mail.

Espero que o post ajude, qualquer dúvida ou crítica podem mandar e-mails ou postar comentários.

Até o próximo post.

Abraços!

0 comentários: