Ruby Language
Singleton Class
Szukaj…
Składnia
- singleton_class = klasa << obiekt; własny koniec
Uwagi
Klasy Singleton mają tylko jedną instancję: odpowiadający im obiekt. Można to zweryfikować poprzez zapytanie ObjectSpace
Ruby:
instances = ObjectSpace.each_object object.singleton_class
instances.count # => 1
instances.include? object # => true
Za pomocą <
można również zweryfikować, że są podklasami rzeczywistej klasy obiektu:
object.singleton_class < object.class # => true
Bibliografia:
Wprowadzenie
Ruby ma trzy typy obiektów:
- Klasy i moduły, które są instancjami klasy Klasa lub Moduł klasy.
- Instancje zajęć.
- Klasy Singleton.
Każdy obiekt ma klasę, która zawiera swoje metody:
class Example
end
object = Example.new
object.class # => Example
Example.class # => Class
Class.class # => Class
Same obiekty nie mogą zawierać metod, tylko ich klasa może. Ale w przypadku klas singletonów można dodawać metody do dowolnego obiektu, w tym innych klas singletonów.
def object.foo
:foo
end
object.foo #=> :foo
foo
jest zdefiniowany dla klasy object
singleton. Inne Example
instancje nie mogą odpowiadać na foo
.
Ruby tworzy klasy singleton na żądanie. Dostęp do nich lub dodawanie do nich metod zmusza Ruby do ich utworzenia.
Dostęp do klasy Singleton
Istnieją dwa sposoby uzyskania pojedynczej klasy obiektu
- metoda
singleton_class
. - Ponowne otwarcie klasy singletonowej obiektu i powrót do
self
.
object.singleton_class
singleton_class = class << object
self
end
Dostęp do zmiennych instancji / klas w klasach Singleton
Klasy Singleton dzielą zmienne instancji / klasy ze swoim obiektem.
class Example
@@foo = :example
end
def Example.foo
class_variable_get :@@foo
end
Example.foo #=> :example
class Example
def initialize
@foo = 1
end
def foo
@foo
end
end
e = Example.new
e.instance_eval <<-BLOCK
def self.increase_foo
@foo += 1
end
BLOCK
e.increase_foo
e.foo #=> 2
Bloki zamykają się wokół celu, dla którego są zmienne instancji / klasy. Dostęp do zmiennych instancji lub klas za pomocą bloku w class_eval
lub instance_eval
nie jest możliwy. Przekazywanie ciągu do class_eval
lub użycie class_variable_get
rozwiązuje problem.
class Foo
@@foo = :foo
end
class Example
@@foo = :example
Foo.define_singleton_method :foo do
@@foo
end
end
Foo.foo #=> :example
Dziedziczenie Singleton Class
Podklasy również podklasy Singleton Class
class Example
end
Example.singleton_class #=> #<Class:Example>
def Example.foo
:example
end
class SubExample < Example
end
SubExample.foo #=> :example
SubExample.singleton_class.superclass #=> #<Class:Example>
Rozszerzenie lub włączenie modułu nie rozszerza klasy Singleton
module ExampleModule
end
def ExampleModule.foo
:foo
end
class Example
extend ExampleModule
include ExampleModule
end
Example.foo #=> NoMethodError: undefined method
Propagacja wiadomości w klasie Singleton
Instancje nigdy nie zawierają metody, w której przenoszą tylko dane. Możemy jednak zdefiniować klasę singletona dla dowolnego obiektu, w tym instancji klasy.
Kiedy wiadomość jest przekazywana do obiektu (wywoływana jest metoda), Ruby najpierw sprawdza, czy dla tego obiektu jest zdefiniowana klasa singleton i czy może odpowiedzieć na tę wiadomość, w przeciwnym razie Ruby sprawdza łańcuch przodków klasy instancji i podchodzi do tego.
class Example
def foo
:example
end
end
Example.new.foo #=> :example
module PrependedModule
def foo
:prepend
end
end
class Example
prepend PrependedModule
end
Example.ancestors #=> [Prepended, Example, Object, Kernel, BasicObject]
e = Example.new
e.foo #=> :prepended
def e.foo
:singleton
end
e.foo #=> :singleton
Ponowne otwarcie (łatanie małp) Klasy Singleton
Istnieją trzy sposoby ponownego otwarcia klasy Singleton
- Użycie
class_eval
w klasie singleton. - Korzystanie z bloku
class <<
. - Użycie
def
do zdefiniowania metody bezpośrednio w klasie singletonowej obiektu
class Example
end
Example.singleton_class.class_eval do
def foo
:foo
end
end
Example.foo #=> :foo
class Example
end
class << Example
def bar
:bar
end
end
Example.bar #=> :bar
class Example
end
def Example.baz
:baz
end
Example.baz #=> :baz
Każdy obiekt ma klasę singleton, do której można uzyskać dostęp
class Example
end
ex1 = Example.new
def ex1.foobar
:foobar
end
ex1.foobar #=> :foobar
ex2 = Example.new
ex2.foobar #=> NoMethodError
Lekcje singletonu
Wszystkie obiekty są instancjami klasy. To jednak nie jest cała prawda. W Ruby każdy obiekt ma również nieco ukrytą klasę singleton .
To pozwala na zdefiniowanie metod dla poszczególnych obiektów. Klasa singleton znajduje się między samym obiektem a jego rzeczywistą klasą, więc wszystkie zdefiniowane w nim metody są dostępne dla tego obiektu i tylko dla tego obiektu.
object = Object.new
def object.exclusive_method
'Only this object will respond to this method'
end
object.exclusive_method
# => "Only this object will respond to this method"
Object.new.exclusive_method rescue $!
# => #<NoMethodError: undefined method `exclusive_method' for #<Object:0xa17b77c>>
Powyższy przykład mógł zostać napisany przy użyciu define_singleton_method
:
object.define_singleton_method :exclusive_method do
"The method is actually defined in the object's singleton class"
end
Która jest taka sama jak określanie sposobu na object
„s singleton_class
:
# send is used because define_method is private
object.singleton_class.send :define_method, :exclusive_method do
"Now we're defining an instance method directly on the singleton class"
end
Przed istnieniem singleton_class
jako części podstawowego API Ruby, klasy singleton były znane jako metaklasy i można było uzyskać do nich dostęp za pomocą następującego idiomu:
class << object
self # refers to object's singleton_class
end