2010-11-18 25 views
14

¿Los métodos y métodos de clase en la clase de genes (o metaclase) de esa clase son solo dos formas de definir una cosa?Ruby Class Métodos vs. Métodos en clases propias

De lo contrario, ¿cuáles son las diferencias?

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

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

hacer X.a y X.b se comportan de manera diferente en alguna forma?

I reconocen que puedo sobrescribir o métodos de clase alias abriendo las 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" 

Respuesta

11

Los dos métodos son equivalentes. La versión 'eigenclass' es útil para el uso de los métodos attr_ *, por ejemplo:

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>] 

También puede utilizar define_singleton_method para crear métodos de la clase:

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

Esta es una respuesta realmente brillante en singletons –

6

En Rubí realmente no hay tal cosas como métodos de clase. Como todo es un objeto en Ruby (incluidas las clases), cuando dices def self.class_method, realmente estás definiendo un método singleton en la instancia de la clase Class. Así que para responder a su pregunta, diciendo

class X 
    def self.a 
    puts "Hi" 
    end 

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

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

hay dos formas de decir lo mismo. Ambos métodos son simplemente métodos singeton (eigen, meta, fantasma o como quiera llamarlos) definidos en la instancia de su objeto Class, que en su ejemplo era X. Este tema es parte de la metaprogramación, que es un tema divertido, que si has estado usando Ruby por un tiempo, deberías echarle un vistazo. Los programadores pragmáticos tienen una gran book en la metaprogramación que definitivamente debería revisar si le interesa el tema.

+2

No estoy de acuerdo en el "No existe el método de clase". Smalltalk ha existido por mucho más tiempo, y también es puro OO y usan la terminología del método de clase todo el tiempo. Decir método de clase es menos confuso que 'singleton' ya que este último es un patrón de diseño y no un atributo de un idioma. –

+1

Podría obtener un premio por necromancia aquí, pero estoy totalmente de acuerdo con "no existe el método de clase". Si defines un método en una clase de objeto y ese objeto es una instancia de 'Perro ', no llamas método a ese método. – ggPeti

+0

Si marca un método con la función ': private_class_method', ciertamente intenta hacerle pensar en él como un método de clase. –

3

Sin embargo, otro nigromante aquí para desenterrar esta vieja pregunta ... Una cosa que podría no ser consciente de que está marcando un método de clase como private (usando la palabra clave privada en lugar de :private_class_method) es diferente que marca un método eigenclass como tal . :

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) 

El siguiente ejemplo de cómo funciona la intención del anterior:

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 mayoría de los métodos de instancia utilizados en Ruby son métodos globales. Eso significa que están disponibles en todas las instancias de la clase en la que se definieron. Por el contrario, un método singleton se implementa en un solo objeto.

Existe una aparente contradicción. Ruby almacena métodos en clases y todos los métodos deben estar asociados con una clase. El objeto sobre el que se define un método singleton no es una clase (es una instancia de una clase). Si solo las clases pueden almacenar métodos, ¿cómo puede un objeto almacenar un método singleton? Cuando se crea un método singleton, Ruby crea automáticamente una clase anónima para almacenar ese método. Estas clases anónimas se llaman metaclases, también conocidas como clases únicas o clases propias. El método singleton está asociado con la metaclase que, a su vez, está asociada con el objeto sobre el que se definió el método singleton.

Si se definen varios métodos únicos dentro de un único objeto, todos se almacenan en la misma metaclase.

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'… 

En el ejemplo anterior, se definió el método say_hello dentro de la instancia z1 de la clase Zen pero no la instancia z2.

El siguiente ejemplo muestra una forma diferente de definir un método singleton, con el mismo resultado.

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'… 

En el ejemplo anterior, la clase < < z1 cambia el auto actual para apuntar a la metaclase del objeto z1; luego, define el método say_hello dentro de la metaclase.

Ambos ejemplos anteriores sirven para ilustrar cómo funcionan los métodos únicos. Sin embargo, existe una manera más fácil de definir un método singleton: usar un método integrado llamado definir_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'… 

Aprendimos anteriormente que las clases también son objetos (instancias de la clase incorporada llamada Clase). También aprendimos sobre métodos de clase. Los métodos de clase no son más que métodos únicos asociados con un objeto de clase.

Un ejemplo más:

class Zabuton 
    class << self 
    def stuff 
     puts "Stuffing zabuton…" 
    end 
    end 
end 

Todos los objetos pueden tener metaclases. Eso significa que las clases también pueden tener metaclases. En el ejemplo anterior, la clase < < se auto modifica por lo que apunta a la metaclase de la clase Zabuton. Cuando se define un método sin un receptor explícito (la clase/objeto sobre el que se definirá el método), se define implícitamente dentro del alcance actual, es decir, el valor actual de uno mismo. Por lo tanto, el método de cosas se define dentro de la metaclase de la clase Zabuton. El ejemplo anterior es solo otra forma de definir un método de clase.

Obtenga más información en this post about Ruby Classes.