2010-11-18 5 views
14

I metodi di classe e i metodi nell'eigenclass (o metaclasse) di tale classe sono solo due modi per definire una cosa?Metodi di classe di ruby ​​rispetto ai metodi nelle vetrature esterne

Altrimenti, quali sono le differenze?

class X 
    # class method 
    def self.a 
    "a" 
    end 

    # eigenclass method 
    class << self 
    def b 
     "b" 
    end 
    end 
end 

fare X.a e X.b si comportano in modo diverso in qualche modo?

riconosco che posso sovrascrivere o metodi della classe alias aprendo le eigenclass:

irb(main):031:0> class X; def self.a; "a"; end; end 
=> nil 
irb(main):032:0> class X; class << self; alias_method :b, :a; end; end 
=> #<Class:X> 
irb(main):033:0> X.a 
=> "a" 
irb(main):034:0> X.b 
=> "a" 
irb(main):035:0> class X; class << self; def a; "c"; end; end; end 
=> nil 
irb(main):036:0> X.a 
=> "c" 

risposta

11

I due metodi sono equivalenti. la versione 'eigenclass' è utile per l'utilizzo dei metodi attr_ *, per esempio:

class Foo 
    @instances = [] 
    class << self; 
    attr_reader :instances 
    end 
    def initialize 
    self.class.instances << self 
    end 
end 

2.times{ Foo.new } 
p Foo.instances 
#=> [#<Foo:0x2a3f020>, #<Foo:0x2a1a5c0>] 

È inoltre possibile utilizzare define_singleton_method per creare metodi sulla classe:

Foo.define_singleton_method :bim do "bam!" end 
+1

Questa è una risposta davvero brillante su singleton –

6

In Ruby non ci sono davvero tali cose come metodi di classe. Poiché tutto è un oggetto in Ruby (comprese le classi), quando si dice def self.class_method, si sta solo definendo un metodo Singleton sull'istanza della classe Class. Quindi, per rispondere alla tua domanda, dire

class X 
    def self.a 
    puts "Hi" 
    end 

    class << self 
    def b 
     puts "there" 
    end 
    end 
end 

X.a # => Hi 
X.b # => there 

è due modi di dire la stessa cosa. Entrambi questi metodi sono solo singeton (eigen, meta, ghost, o qualsiasi altra cosa si voglia chiamare) metodi definiti nell'istanza dell'oggetto Class, che nell'esempio è stato X. Questo argomento fa parte della metaprogrammazione, che è un argomento divertente, che se hai usato Ruby per un po ', dovresti dare un'occhiata. I programmatori pragmatici hanno un ottimo book sulla metaprogrammazione che dovresti assolutamente dare un'occhiata se sei interessato all'argomento.

+2

Non sono d'accordo sul tema "Non esiste il metodo di classe". Smalltalk è in circolazione da molto più tempo ed è anche OO puro e usano sempre la terminologia del metodo di classe. Dire il metodo di classe è meno confusionario di "singleton" dato che quest'ultimo è un modello di progettazione e non un attributo di una lingua. –

+1

Qui potrei ricevere un premio per la negromanzia, ma sono assolutamente d'accordo sul fatto che "non esiste un metodo di classe". Se definisci un metodo sull'eigenclass di un oggetto e quell'oggetto è un'istanza di 'Dog', non chiami quel metodo come metodo dog. – ggPeti

+0

Se si contrassegna un metodo con la funzione ': private_class_method', sicuramente cerca di farvi pensare a un metodo di classe. –

3

Ancora un altro necromante qui per portare alla luce questa vecchia domanda ... Una cosa di cui non si può essere a conoscenza è che contrassegnare un metodo di classe come private (usando la parola chiave privata invece di :private_class_method) è diverso da quello di contrassegnare un metodo eigenclass come tale . :

class Foo 
    class << self 
    def baz 
     puts "Eigenclass public method." 
    end 

    private 
    def qux 
     puts "Private method on eigenclass." 
    end 
    end 
    private 
    def self.bar 
    puts "Private class method." 
    end 
end 

Foo.bar 
#=> Private class method. 
Foo.baz 
#=> Eigenclass public method. 
Foo.qux 
#=> NoMethodError: private method `qux' called for Foo:Class 
# from (irb) 

Il seguente esempio funziona come quella precedente intende:

class Foo 
    class << self 
    def baz 
     puts "Eigen class public method." 
    end 

    private 
    def qux 
     puts "Private method on eigenclass." 
    end 
    end 
    def bar 
    puts "Private class method." 
    end 
    private_class_method :bar 
end 
Foo.bar 
#=> NoMethodError: private method `bar' called for Foo:Class 
#  from (irb) 
Foo.baz 
#=> Eigen class public method. 
Foo.qux 
#=> NoMethodError: private method `qux' called for Foo:Class 
#  from (irb) 
1

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.

Problemi correlati