Controllo d'accesso
Precedentemente, abbiamo detto che ruby non ha funzioni, ma solo metodi. Comunque esistono più tipi di metodi . In questo capitolo introduciamo il controllo d'accesso.
Immaginate ciò che accade quando definiamo un metodo nel "livello più alto" , cioè fuori da una definizione di classe. Possiamo pensare ad un tale metodo come ad una funzione in un linguaggio più tradizionale come il C.
ruby> def quadrato(n)
| n * n
| end
nil
ruby> quadrato(5)
25
Il nostro nuovo metodo sembrerà non appartere a
nessuna classe, ma in effetti ruby lo mette nela classe
Object , che è la superclasse di ogni
altra. Come risultato, ogni oggetto ora dovrebbe essere in
grado di poter usare quel metodo . Questa cosa
risulterà essere vera, ma c'è un dettaglio:
si tratta di un metodo privato di ogni classe.
Discuteremo un po' di cosa significa questa dichiarazione
più avanti, ma una delle conseguenza è che
potrà essere invocato solo in “stile
funzione”:
ruby> class Foo
| def quarta_potenza_di(x)
| quadrato(x) * quadrato(x)
| end
| end
nil
ruby> Foo.new.quarta_potenza_di 10
10000
Non ci è permesso di applicare esplicitamente il metodo su di un oggetto:
ruby> "pesce".quadrato(5) ERR: (eval):1: private method `square' called for "pesce":String
Ciò preserva in maniera intelligente la natura
puramente OO di ruby (le funzioni sono ancora metodi degli
oggetti, ma il ricevitore è
implicitamenteself ) pur fornendo funzioni che
possono essere scritte come in un linguaggio tradizionale.
Una disciplina mentale comune nella programmazione OO, alla
quale abiamo fatto rigferimento in un capitolo precedente,
riguarda la separazone tra specifica ed
implementazione, o tra quali compiti si
suppone che vengano svolti da un oggetto e come
vengono effettivamente svolti. Il funzionamento interno di un
oggetto dovrebbe generalmente essere mantenuto nascosto ai
suoi utilizzatori; essi dovrebbero soltanto preoccuparsi di
cosa entra e cosa esce, e fidarsi che l'oggetto sappia
quelloche deve fare al suo interno. Ad esempio spesso
è utile avere nelle classi dei metodi che il mondo
esterno non vede, ma che sono usati internamente (e possono
essere migliorati dal programmatore quando si vuole, senza
cambiare il modo in cui gli uytenti vedono gli oggetti della
classe). Nel seguente semplice esempio, pensate a
engine come al lavoro interno ed invisibile
della classe.
ruby> class Prova
| def volte_due(a)
| print a," volte due e' " ,engine(a),""
| end
| def engine(b)
| b*2
| end
| private:engine # questo nasconde engine all'utente
| end
Test
ruby> test = Test.new
#<Test:0x4017181c>
ruby> test.engine(6)
ERR: (eval):1: private method `engine' called for #<Test:0x4017181c>
ruby> test.volte_due(6)
6 volte due e' 12.
nil
Potremmo esserci aspettati che test.engine(6)
ritornasse 12, ma invece vediamo che engine
è inaccessibile quando agiamo come utenti esterni a
Prova. Solo ai metodi di Prova,
come volte_due, viene permesso di usare
engine. Abbiamo bisogno di passare attraverso
l'interfaccia pubblica, che consiste nel metodo
volte_due . Il programmatore che è
responsabile di questa classe può cambiare
engine liberamente (qui, forse cambiando
b*2 con b+b, assumendo che
ciò porti a prestazioni migliori) senza infastidire il
modo in cui l'utente interagisce con gli oggetti
Prova. Questo esempio ovviamente è troppo
semplice per essere utile; i benfici del controllo
d'accesso diventano più chiari quando cominciamo a
creare classi più complesse ed interessanti .