Uită-te la orice cod orientat pe obiect și totul mai mult sau mai puțin urmează același tipar. Creați un obiect, apelați la anumite metode pe acel obiect și accesați atributele acelui obiect. Nu puteți face altceva cu un obiect decât să-l treceți ca parametru la metoda altui obiect. Dar ceea ce ne preocupă aici sunt atributele.
Atributele sunt ca. variabile de instanta puteți accesa prin notarea punctului obiect. De exemplu, person.name ar accesa numele unei persoane. În mod similar, puteți atribui adesea atribute de genul person.name = "Alice". Aceasta este o caracteristică similară cu variabilele de membru (cum ar fi în C ++), dar nu chiar la fel. Nu se întâmplă nimic special aici, atributele sunt implementate în majoritatea limbilor folosind „getters” și „setters” sau metode care regăsesc și setează atributele din variabilele de instanță.
Ruby nu face o distincție între getters și setters de atribute și metode normale. Din cauza metodei flexibile a lui Ruby, care face apel la sintaxa, nu trebuie făcută nicio distincție. De exemplu,
person.name și person.name () sunt același lucru, sunteți Nume metoda cu parametri zero. Unul arata ca un apel de metoda, iar celalalt arata ca un atribut, dar ambele sunt acelasi lucru. Amândoi sună doar Nume metodă. În mod similar, orice nume de metodă care se încheie într-un semn egal (=) poate fi utilizat într-o misiune. Declaratia person.name = "Alice" este cu adevărat același lucru ca și person.name = (alice)Chiar dacă există un spațiu între numele atributului și semnul egal, acesta este încă apelând la nume = metodă.Puteți implementa cu ușurință atributele singuri. Prin definirea metodelor setter și getter, puteți implementa orice atribut doriți. Iată câteva exemple de cod care implementează Nume atribut pentru o clasă de persoană. Stochează numele într-un @Nume variabilă de instanță, dar numele nu trebuie să fie același. Nu uitați, nu este nimic special în ceea ce privește aceste metode.
Un lucru pe care îl veți observa imediat este faptul că este multă muncă. Tastați doar pentru a spune că doriți un atribut numit Nume care accesează @Nume variabila de instanta. Din fericire, Ruby oferă câteva metode de comoditate care vor defini aceste metode pentru dvs.
Există trei metode în Modul clasă pe care o puteți utiliza în interiorul declarațiilor de clasă. Nu uitați că Ruby nu face nici o distincție între timpul de rulare și „compilarea timpului”, iar orice cod din interiorul declarațiilor clasei nu poate doar să definească metode, ci și metode de apel. Apelarea la attr_reader, attr_writer și attr_accessor la rândul lor, metodele vor defini seterii și getter-urile pe care ni le-am definit în secțiunea anterioară.
attr_reader metoda face exact ceea ce sună ca și cum va face. Este nevoie de orice număr de parametri de simbol și, pentru fiecare parametru, definește o metodă "getter" care returnează variabila de instanță cu același nume. Deci, ne putem înlocui Nume metoda din exemplul precedent cu attr_reader: nume.
În mod similar, attr_writer metoda definește o metodă „setter” pentru fiecare simbol care i-a fost transmis. Rețineți că semnul egal nu trebuie să facă parte din simbol, ci doar numele atributului. Putem înlocui nume = metoda din exemplul anterior cu un apel la attr_writier: nume.
Și, așa cum era de așteptat, attr_accessor face treaba amândurora attr_writer și attr_reader. Dacă aveți nevoie atât de un setter, cât și de un getter pentru un atribut, este o practică obișnuită să nu apelați cele două metode separat și să apelați în schimb attr_accessor. Am putea înlocui ambii Nume și nume = metode din exemplul anterior cu un singur apel la attr_accessor: nume.
De ce ar trebui să definiți manual setatorii? De ce nu folosiți attr_ * metode de fiecare dată? Pentru că rup încapsularea. Încapsularea este principalul care declară că nicio entitate externă nu ar trebui să aibă acces fără restricții la starea internă a dvs. obiecte. Trebuie accesat totul folosind o interfață care împiedică utilizatorul să corupe starea internă a obiectului. Folosind metodele de mai sus, am perforat o gaură mare în peretele nostru de încapsulare și am permis să fie setat absolut orice pentru un nume, chiar și nume invalide, evident.
Un lucru pe care îl veți vedea adesea este acela attr_reader va fi folosit pentru a defini rapid un getter, dar un setter personalizat va fi definit deoarece starea internă a obiectului dorește adesea să fie citit direct din starea internă. Seterul este apoi definit manual și verifică pentru ca valoarea setată să aibă sens. Sau, poate mai frecvent, niciun setter nu este definit deloc. Celelalte metode din funcția de clasă setează variabila de instanță în spatele getterului într-un alt mod.
Acum putem adăuga un vârstă și implementați corect a Nume atribut. vârstă atributul poate fi setat în metoda constructorului, citit folosind funcția vârstă getter, dar manipulat doar folosind have_birthday metoda, care va crește vârsta. Nume atributul are un getter normal, dar setterul se asigură că numele este scris cu majuscule și are forma Prenume Prenume.