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


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow