De ce să folosiți Ruby's attr_accessor, attr_reader și attr_writer?

Ruby are la îndemână și convenabil mod de a partaja variabile de instanta prin utilizarea de chei, cum ar fi

attr_accessor :var
attr_reader :var
attr_writer :var

De ce as alege attr_reader " sau " attr_writer dacă am putea folosi pur și simpluattr_accessor`? Este ceva ca de performanță (ceea ce ma indoiesc)? Cred că există un motiv, altfel nu le-ar't au făcut astfel de chei.

Comentarii la întrebare (1)
Soluția

Puteți utiliza diferite evaluatorilor de a comunica intenția de a cineva a citit codul, și face mai ușor pentru a scrie clase care vor funcționa corect indiferent de modul lor de API-ul public este numit.

class Person
  attr_accessor :age
  ...
end

Aici, văd că am putea citi și scrie în vârstă.

class Person
  attr_reader :age
  ...
end

Aici, eu pot vedea că eu pot citi doar de vârstă. Imaginați-vă că acesta este stabilit de către constructor din această clasă și după care rămâne constantă. Dacă ar exista un mutator (scriitor) pentru vârstă și clasă au fost scrise, presupunând că vârsta, odată stabilit, nu se modifică, atunci un bug care ar putea rezulta din codul de asteptare, care mutator.

Dar ceea ce se întâmplă în spatele scenei?

Dacă ați scrie:

attr_writer :age

Asta se traduce în:

def age=(value)
  @age = value
end

Dacă ați scrie:

attr_reader :age

Asta se traduce în:

def age
  @age
end

Dacă ați scrie:

attr_accessor :age

Asta se traduce în:

def age=(value)
  @age = value
end

def age
  @age
end

Știind că, aici's un alt mod de a gândi despre ea: Dacă nu ai avea attr_... ajutoare, și a trebuit să scrie evaluatorilor tine, ai mai scrie evaluatorilor decât clasa nevoie? De exemplu, dacă vârsta necesară doar pentru a fi citit, ai scrie, de asemenea, o metodă care să îi permită să fi scris?

Comentarii (10)

Toate răspunsurile de mai sus sunt corecte; attr_reader " și " attr_writer sunt mult mai convenabil pentru a scrie decât tastarea manual metodele sunt shorthands pentru. În afară de faptul că acestea oferă o performanță mult mai bună decât scrierea metoda definiție tine. Pentru mai multe informații a se vedea diapozitiv 152 începând din această discuție (PDF) de către Aaron Patterson.

Comentarii (0)

Nu toate atributele unui obiect sunt menite să fie stabilite direct din afara clasei. Având scriitori pentru toate variabilele instanță este în general un semn de slab încapsulare și un avertisment ca're introducerea prea mult de cuplare între clase.

Ca un exemplu practic: am scris un program de proiectare în cazul în care puneți obiecte în interiorul containerelor. Elementul a `attr_reader :recipient, dar nu't face sens pentru a oferi un scriitor, deoarece singura dată când elementul's container ar trebui să se schimbe este atunci când l's-a plasat într-unul nou, care necesită, de asemenea, informații de poziționare.

Comentarii (0)

Nu't întotdeauna vrei variabile de instanta pentru a fi pe deplin accesibil din afara clasei. Există o mulțime de cazuri în care permite acces de citire la o instanță variabilă are sens, dar de scris pentru că nu s-ar putea (de exemplu, un model care preia datele dintr-o citi-singura sursă). Există cazuri în cazul în care doriți opus, dar nu pot't cred că de orice, care nu't contrived pe partea de sus a capul meu.

Comentarii (0)

Este important să înțelegem că evaluatorilor restricționa accesul la variabile, dar nu și conținutul lor. În ruby, ca și în alte OO limbi, fiecare variabilă este un pointer la o instanță. Deci, dacă aveți un atribut la un Hash, de exemplu, și setați-l pentru a fi "citi doar" mereu ai putea schimba conținutul său, dar nu și conținutul indicatorului. Uită-te la asta:

irb(main):024:0> class A
irb(main):025:1> attr_reader :a
irb(main):026:1> def initialize
irb(main):027:2> @a = {a:1, b:2}
irb(main):028:2> end
irb(main):029:1> end
=> :initialize
irb(main):030:0> a = A.new
=> #1, :b=>2}>
irb(main):031:0> a.a
=> {:a=>1, :b=>2}
irb(main):032:0> a.a.delete(:b)
=> 2
irb(main):033:0> a.a
=> {:a=>1}
irb(main):034:0> a.a = {}
NoMethodError: undefined method `a=' for #1}>
        from (irb):34
        from /usr/local/bin/irb:11:in `'

După cum puteți vedea, este posibil să ștergeți o cheie/valoare pereche de Hash @o, așa cum se adaugă noi chei, modificați valorile, eccetera. Dar poate't punctul la un obiect nou pentru că este o citesc doar variabilă de exemplu.

Comentarii (0)