Większość metod instancji używane w Ruby są metody globalne. Oznacza to, że są one dostępne we wszystkich instancjach klasy, w której zostały zdefiniowane. Natomiast metoda pojedyncza jest zaimplementowana na pojedynczym obiekcie.
Istnieje widoczna sprzeczność. Ruby przechowuje metody w klasach i wszystkie metody muszą być powiązane z klasą. Obiekt, w którym zdefiniowana jest metoda singleton, nie jest klasą (jest instancją klasy). Jeśli tylko klasy mogą przechowywać metody, w jaki sposób obiekt może przechowywać metodę singleton? Po utworzeniu metody singleton, Ruby automatycznie tworzy anonimową klasę do przechowywania tej metody. Te anonimowe klasy nazywane są metaclasses, zwane również klasami singleton lub eigenclasses. Metoda singleton jest powiązana z metaclass, która z kolei jest powiązana z obiektem, na którym została zdefiniowana metoda singleton.
Jeśli w pojedynczym obiekcie zdefiniowano wiele metod singletowych, wszystkie są przechowywane w tym samym metaclassie.
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'…
W powyższym przykładzie metoda say_hello została zdefiniowana w instancji z1 klasy Zen, ale nie w instancji z2.
Poniższy przykład ilustruje inny sposób definiowania metody singleton z tym samym wynikiem.
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'…
W powyższym przykładzie, klasa < < Z1 zmienia bieżący siebie punkt do metaklasą przedmiotu z1; następnie definiuje metodę say_hello w metaclassie.
Oba powyższe przykłady służą do zilustrowania działania metod singletowych. Istnieje jednak łatwiejszy sposób zdefiniowania metody singleton: za pomocą wbudowanej metody o nazwie 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'…
Nauczyliśmy się wcześniej, że klasy są również obiektami (wystąpienia wbudowanej klasy zwanej klasą). Dowiedzieliśmy się również o metodach klasowych. Metody klasy nie są niczym więcej niż metodami singleton powiązanymi z obiektem klasy.
Jeszcze jeden przykład:
class Zabuton
class << self
def stuff
puts "Stuffing zabuton…"
end
end
end
Wszystkie obiekty mogą mieć metaclasses. Oznacza to, że klasy mogą mieć również metaclasy. W powyższym przykładzie klasa < < samo siebie modyfikuje, więc wskazuje na metaklas klasy Zabuton. Gdy metoda jest zdefiniowana bez jawnego odbiorcy (klasa/obiekt, na którym zostanie zdefiniowana metoda), jest niejawnie zdefiniowana w ramach bieżącego zakresu, czyli bieżącej wartości ja. Stąd metoda stuff jest zdefiniowana w metaklasy klasy Zabuton. Powyższy przykład jest po prostu kolejnym sposobem zdefiniowania metody klasy.
Czytaj więcej na this post about Ruby Classes.
To jest naprawdę genialna odpowiedź na singletons –