La maggior parte dei metodi di istanza utilizzati in Ruby sono metodi globali. Ciò significa che sono disponibili in tutte le istanze della classe in cui sono stati definiti. Al contrario, un metodo Singleton è implementato su un singolo oggetto.
C'è un'apparente contraddizione. Ruby memorizza i metodi nelle classi e tutti i metodi devono essere associati a una classe. L'oggetto su cui viene definito un metodo Singleton non è una classe (è un'istanza di una classe). Se solo le classi possono memorizzare metodi, come può un oggetto memorizzare un metodo singleton? Quando viene creato un metodo Singleton, Ruby crea automaticamente una classe anonima per memorizzare quel metodo. Queste classi anonime sono chiamate metaclassi, note anche come classi singleton o eigenclasses. Il metodo Singleton è associato al metaclasse che, a sua volta, è associato all'oggetto su cui è stato definito il metodo Singleton.
Se più metodi singleton sono definiti all'interno di un singolo oggetto, vengono tutti memorizzati nello stesso metaclasse.
class Zen
end
z1 = Zen.new
z2 = Zen.new
def z1.say_hello # Notice that the method name is prefixed with the object name
puts "Hello!"
end
z1.say_hello # Output: Hello!
z2.say_hello # Output: NoMethodError: undefined method `say_hello'…
Nell'esempio precedente, il metodo say_hello stata definita all'interno dell'istanza z1 della classe Zen ma non l'istanza z2.
L'esempio seguente mostra un modo diverso per definire un metodo Singleton, con lo stesso risultato.
class Zen
end
z1 = Zen.new
z2 = Zen.new
class << z1
def say_hello
puts "Hello!"
end
end
z1.say_hello # Output: Hello!
z2.say_hello # Output: NoMethodError: undefined method `say_hello'…
Nell'esempio precedente, classe < < z1 cambia l'angolo corrente per puntare alla metaclasse dell'oggetto z1; quindi, definisce il metodo say_hello nel metaclass.
Entrambi gli esempi precedenti servono a illustrare come funzionano i metodi Singleton. Esiste, tuttavia, un modo più semplice per definire un metodo Singleton: utilizzando un metodo predefinito chiamato define_singleton_method.
class Zen
end
z1 = Zen.new
z2 = Zen.new
z1.define_singleton_method(:say_hello) { puts "Hello!" }
z1.say_hello # Output: Hello!
z2.say_hello # Output: NoMethodError: undefined method `say_hello'…
Abbiamo imparato prima che le classi sono anche oggetti (istanze della classe built-in chiamata Classe). Abbiamo anche imparato a conoscere i metodi di classe. I metodi di classe non sono altro che i metodi Singleton associati a un oggetto di classe.
Un altro esempio:
class Zabuton
class << self
def stuff
puts "Stuffing zabuton…"
end
end
end
Tutti gli oggetti possono avere metaclassi. Ciò significa che le classi possono anche avere metaclassi. Nell'esempio precedente, la classe < < si auto modifica in modo che punti al metaclasse della classe Zabuton. Quando un metodo viene definito senza un destinatario esplicito (la classe/oggetto su cui verrà definito il metodo), esso viene implicitamente definito nell'ambito corrente, cioè il valore corrente di sé. Quindi, il metodo stuff è definito all'interno del metaclass della classe Zabuton. L'esempio sopra è solo un altro modo per definire un metodo di classe.
Ulteriori informazioni allo this post about Ruby Classes.
Questa è una risposta davvero brillante su singleton –