O Ruby tem essa maneira prática e conveniente de compartilhar variáveis de instância usando chaves como
attr_accessor :var
attr_reader :var
attr_writer :var
Por que eu escolheria attr_reader
ou attr_writer
se poderia simplesmente usar attr_accessor
? Existe algo como desempenho (do qual duvido)? Eu acho que há uma razão, caso contrário eles não teriam feito essas chaves.
Respostas:
Você pode usar os diferentes acessadores para comunicar sua intenção a alguém que está lendo seu código e facilitar a gravação de classes que funcionarão corretamente, independentemente de como a API pública seja chamada.
Aqui, vejo que posso ler e escrever a era.
Aqui, vejo que só posso ler a idade. Imagine que ele é definido pelo construtor dessa classe e depois disso permanece constante. Se houvesse um mutador (escritor) para a idade e a classe fosse escrita assumindo que a idade, uma vez definida, não muda, um bug pode resultar do código que chama esse mutador.
Mas o que está acontecendo nos bastidores?
Se você escrever:
Isso é traduzido para:
Se você escrever:
Isso é traduzido para:
Se você escrever:
Isso é traduzido para:
Sabendo disso, eis outra maneira de pensar sobre isso: Se você não tivesse os auxiliares de atributos e tivesse que escrever os acessadores por si mesmo, escreveria mais acessadores do que a sua classe precisava? Por exemplo, se a idade apenas precisasse ser lida, você também escreveria um método que permitisse que ela fosse escrita?
fonte
attr_reader :a
vs.def a; return a; end
confreaks.net/videos/...attr_reader
acessador definido leva 86% do tempo que o acessador definido manualmente. Para o Ruby 1.9.0, oattr_reader
acessador definido leva 94% do tempo que o acessador definido manualmente. Em todos os meus testes, no entanto, os acessadores são rápidos: um acessador leva cerca de 820 nanossegundos (Ruby 1.8.7) ou 440 nanossegundos (Ruby 1.9). Nessas velocidades, você precisará ligar para um acessador centenas de milhões de vezes para obter o benefício de desempenhoattr_accessor
para melhorar o tempo de execução geral em até um segundo.attr_accessor :a, :b
Todas as respostas acima estão corretas;
attr_reader
eattr_writer
é mais conveniente escrever do que digitar manualmente os métodos para os quais são abreviados. Além disso, eles oferecem desempenho muito melhor do que você mesmo escrevendo a definição do método. Para mais informações, consulte o slide 152 em diante desta palestra ( PDF ) de Aaron Patterson.fonte
Nem todos os atributos de um objeto devem ser definidos diretamente de fora da classe. Ter gravadores para todas as variáveis de instância é geralmente um sinal de encapsulamento fraco e um aviso de que você está introduzindo muito acoplamento entre suas classes.
Como exemplo prático: escrevi um programa de design em que você coloca itens dentro de contêineres. O item tinha
attr_reader :container
, mas não fazia sentido oferecer a um escritor, pois o único momento em que o contêiner do item deve mudar é quando ele é colocado em um novo, o que também requer informações de posicionamento.fonte
É importante entender que os acessadores restringem o acesso à variável, mas não ao conteúdo. Em ruby, como em outras linguagens OO, toda variável é um ponteiro para uma instância. Portanto, se você possui um atributo para um Hash, por exemplo, e o define como "somente leitura", sempre pode alterar o conteúdo, mas não o conteúdo do ponteiro. Veja isso:
Como você pode ver, é possível excluir um par de chave / valor do Hash @a, como adicionar novas chaves, alterar valores, etc. Mas você não pode apontar para um novo objeto porque é uma variável de instância somente leitura.
fonte
Você nem sempre deseja que suas variáveis de instância sejam totalmente acessíveis de fora da classe. Existem muitos casos em que permitir o acesso de leitura a uma variável de instância faz sentido, mas a gravação pode não ser (por exemplo, um modelo que recupera dados de uma fonte somente leitura). Há casos em que você deseja o contrário, mas não consigo pensar em nenhum que não seja inventado do alto da minha cabeça.
fonte