Ruby Privato i Metodi della Classe

24 Jan 2016

Nel linguaggio di programmazione Ruby, definiti i metodi sono disponibili in due varianti: metodi di istanza e metodi di classe. I metodi di istanza sono disponibili dopo che un oggetto è stato inizializzato, creando un’istanza. I metodi di classe, d’altra parte, sono disponibili senza creare un’istanza della classe su cui sono definiti.

I metodi Ruby possono variare in visibilità. I metodi pubblici sono disponibili in qualsiasi contesto, mentre la disponibilità dei metodi privati è limitata all’interno dell’istanza di una classe e dei suoi discendenti. Un terzo ambito di visibilità, protetto, si comporta in modo simile ai metodi privati, ma i metodi protetti possono essere chiamati da altre istanze della stessa classe.

Per un rapido aggiornamento, i metodi di istanza pubblici e privati sono simili a questi:

class Dog def do_trick bark end private def bark puts 'woof woof' endend

Quando viene chiamato il metodo pubblico:

> dog = Dog.new> dog.do_trick# => woof woof

E il metodo privato:

> dog = Dog.new> dog.bark# => NoMethodError: private method `bark' called for <Dog>

I metodi di classe privata potrebbero non essere comuni come i metodi di istanza privata, ma hanno ancora il loro posto. Ad esempio, un metodo di classe può richiedere metodi di supporto interni per completare la sua funzione. Qualunque sia la ragione, la definizione di metodi di classe privata ha valore ma non è sempre intuitiva.

Questa classe di esempio Dog deve mantenere un elenco di tricks che verrà utilizzato all’interno degli altri metodi di classe pubblica. Questo elenco non dovrebbe essere accessibile a tutti i chiamanti al di fuori della classe Dog.

Il modo sbagliato

Un primo passo in scrittura privata tricks metodo potrebbe apparire come:

class Dog private def self.tricks endend

Tuttavia, quando si verifica la visibilità dei tricks metodo:

> Dog.tricks# => 

Uh oh, nessun errore è stato gettato indicando che un metodo privato è stato chiamato, questo metodo è completamente pubblico.

Perché?

La ragione per cui il codice sopra non ha prodotto un metodo privato ha a che fare con la gerarchia degli oggetti di Ruby, le interazioni tra le classi interne, le istanze di quelle classi e le eigenclasses. Un articolo dettagliato su come gli oggetti di Ruby funzionano l’uno con l’altro può essere trovato in un post precedente.

Quando si definiscono i metodi in una classe, il contesto predefinito e il contesto introdotto dalla dichiarazione del metodo self. sono distinti.

L’ambito del metodo privato non può essere utilizzato nel modo precedente in quanto non gestisce il cambiamento di contesto tra i metodi definiti nella classe Dog e definiti nel contesto self.

Quindi quali sono le alternative?

class < <self

Un modo alternativo per definire i metodi di classe su un oggetto è usare la sintassi class << self. Questa sintassi apre una eigenclass per l’argomento fornito. In questo esempio, self all’interno della classe Dog si aprirà la classe di emissione Dog's.

class Dog class << self private def tricks end endend

Una cosa da notare è che quando si definiscono metodi come questo, la dichiarazione è cambiata da def self.tricks a semplicemente def tricks.

Ora, l’ambito privato viene preservato e il comportamento previsto viene raggiunto:

> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class

Moduli

I moduli in ruby sono raccolte di metodi e costanti. Queste raccolte possono essere utilizzate come strumenti di incapsulamento o, in questo caso, alternative alla definizione di metodi di classe pubblici e privati.

Quando una classe extends un modulo, tutti i metodi all’interno di quel modulo diventano metodi di classe sulla classe oggetto*. Questo modello può essere utilizzato per definire il metodo tricks su Dog.

*Nota: Questo riguarda solo i metodi definiti in un” senso tipico ” qualsiasi definizione di metodo def self. o def Dog. in un modulo non diventa automaticamente metodi di classe allo stesso modo quando extended.

class Dog module ClassMethods private def tricks end end extend ClassMethodsend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class

Un vantaggio di questo approccio è la leggibilità. Il modulo denominato ClassMethods, che è contenuto e quindi incapsulato dalla classe Dog, è la casa chiara per tutti i metodi di classe desiderati.

I modificatori di visibilità come private si comportano di conseguenza e un semplice extend nella parte inferiore della definizione del modulo riunisce tutto.

private_class_method

Un terzo approccio consiste nell’utilizzare il metodo integrato Module#private_class_method. Lo scopo di questo metodo è quello di modificare la visibilità dei metodi di classe esistenti.

a Differenza delle altre due soluzioni, questo non ha bisogno di un diverso stile di definizione del metodo non corretto soluzione:

class Dog def self.tricks end private_class_method :tricksend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class

Questo metodo può anche essere in-foderato durante il classe’ metodo di definizione:

class Dog private_class_method def self.tricks endend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class

Se un singolo metodo di classe deve essere privata e risparmio di linee è molto importante, questo stile potrebbe essere applicabile; ma, certamente sacrifica un livello di leggibilità.

Un importante punto di forza di private_class_method è la sua esplicitezza. A differenza degli altri approcci, questo non richiede una definizione di modulo speciale o una commutazione di contesto della definizione del metodo.

Ulteriori letture

Le soluzioni di cui sopra porteranno a termine il lavoro, ma potrebbero non rispondere a domande persistenti sul perché le cose funzionino nel modo in cui funzionano. Alcuni grandi articoli su ruby eigenclass e i pensieri di Matz sulla progettazione del metodo Ruby dovrebbero aiutare a dipingere un quadro più conciso del perché la definizione del metodo di classe privata di Ruby è complessa.

You might also like

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.