Guarda qualsiasi codice orientato agli oggetti e tutto segue più o meno lo stesso modello. Crea un oggetto, chiama alcuni metodi su quell'oggetto e accedi agli attributi di quell'oggetto. Non c'è molto altro che puoi fare con un oggetto tranne che passarlo come parametro al metodo di un altro oggetto. Ma ciò di cui ci occupiamo qui sono gli attributi.
Gli attributi sono come variabili di istanza è possibile accedere tramite la notazione a punti dell'oggetto. Per esempio, person.name accederebbe al nome di una persona. Allo stesso modo, puoi spesso assegnare ad attributi come person.name = "Alice". Questa è una funzione simile alle variabili membro (come in C ++), ma non è la stessa cosa. Non sta succedendo nulla di speciale qui, gli attributi sono implementati nella maggior parte delle lingue usando "getter" e "setter" o metodi che recuperano e impostano gli attributi dalle variabili di istanza.
Ruby non fa una distinzione tra getter e setter di attributi e metodi normali. A causa del metodo flessibile di Ruby che chiama la sintassi, non è necessario fare alcuna distinzione. Per esempio,
person.name e person.name () sono la stessa cosa, stai chiamando il nome metodo con zero parametri. Uno sembra una chiamata di metodo e l'altro sembra un attributo, ma sono davvero entrambi la stessa cosa. Entrambi stanno solo chiamando il nome metodo. Allo stesso modo, qualsiasi nome di metodo che termina con un segno di uguale (=) può essere utilizzato in un compito. La dichiarazione person.name = "Alice" è davvero la stessa cosa di person.name = (Alice), anche se c'è uno spazio tra il nome dell'attributo e il segno di uguale, sta ancora chiamando il name = metodo.Puoi facilmente implementare gli attributi da solo. Definendo i metodi setter e getter, è possibile implementare qualsiasi attributo desiderato. Ecco alcuni esempi di codice che implementano il nome attributo per una classe persona. Memorizza il nome in a @nome variabile di istanza, ma il nome non deve essere lo stesso. Ricorda, non c'è niente di speciale in questi metodi.
Una cosa che noterai subito è che si tratta di molto lavoro. È molto digitando solo per dire che vuoi un attributo chiamato nome che accede al @nome variabile di istanza. Fortunatamente, Ruby fornisce alcuni metodi di praticità che definiranno questi metodi per te.
Ci sono tre metodi in Modulo classe che è possibile utilizzare all'interno delle dichiarazioni di classe. Ricorda che Ruby non fa distinzione tra runtime e "tempo di compilazione" e che qualsiasi codice all'interno delle dichiarazioni di classe non può solo definire metodi ma anche chiamare metodi. Chiamando il attr_reader, attr_writer e attr_accessor i metodi, a loro volta, definiranno i setter e i getter che stavamo definendo nella sezione precedente.
Il attr_reader il metodo piace proprio come sembra che farà. Prende un numero qualsiasi di parametri simbolo e, per ciascun parametro, definisce un metodo "getter" che restituisce la variabile di istanza con lo stesso nome. Quindi, possiamo sostituire il nostro nome metodo nell'esempio precedente con attr_reader: nome.
Allo stesso modo, il attr_writer Il metodo definisce un metodo "setter" per ciascun simbolo passato ad esso. Si noti che il segno di uguale non deve necessariamente essere parte del simbolo, ma solo il nome dell'attributo. Possiamo sostituire il name = metodo dell'esempio precedente con una chiamata a attr_writier: nome.
E, come previsto, attr_accessor fa il lavoro di entrambi attr_writer e attr_reader. Se hai bisogno sia di un setter che di un getter per un attributo, è pratica comune non chiamare i due metodi separatamente e invece chiamare attr_accessor. Potremmo sostituire tutti e due il nome e name = metodi dell'esempio precedente con una singola chiamata a attr_accessor: nome.
Perché dovresti definire manualmente i setter? Perché non usare il attr_ * metodi ogni volta? Perché rompono l'incapsulamento. L'incapsulamento è il principio che afferma che nessuna entità esterna dovrebbe avere accesso illimitato allo stato interno del tuo oggetti. È necessario accedere a tutto utilizzando un'interfaccia che impedisce all'utente di corrompere lo stato interno dell'oggetto. Usando i metodi sopra, abbiamo creato un grande buco nel nostro muro di incapsulamento e permesso di impostare qualsiasi cosa per un nome, anche ovviamente nomi non validi.
Una cosa che vedrai spesso è quella attr_reader verrà utilizzato per definire rapidamente un getter, ma verrà definito un setter personalizzato poiché lo stato interno dell'oggetto spesso vuole essere leggere direttamente dallo stato interno. Il setter viene quindi definito manualmente e verifica che il valore impostato abbia senso. O, forse più comunemente, nessun setter è definito affatto. Gli altri metodi nella funzione di classe impostano la variabile di istanza dietro il getter in qualche altro modo.
Ora possiamo aggiungere un età e implementare correttamente a nome attributo. Il età l'attributo può essere impostato nel metodo di costruzione, letto usando il età getter ma solo manipolato usando il have_birthday metodo, che aumenterà l'età. Il nome L'attributo ha un normale getter, ma il setter si assicura che il nome sia in maiuscolo e sia nella forma di Nome e cognome.