2010-11-18 11 views
14

Czy metody i metody klasowe w eigenclass (lub metaclass) tej klasy są tylko dwoma sposobami zdefiniowania jednej rzeczy?Metody klasy Ruby a metody w klasach adresów

W przeciwnym razie, jakie są różnice?

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

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

Czy X.a i X.b zachowują się inaczej w jakikolwiek sposób?

uznaję, że można zastępować lub sposoby klasy ps otwierając 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" 

Odpowiedz

11

Obie metody są równoważne. Wersja „eigenclass” jest pomocne przy użyciu metod attr_ *, na przykład:

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

Można również wykorzystać define_singleton_method stworzyć metody na klasę:

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

To jest naprawdę genialna odpowiedź na singletons –

6

w Ruby tam naprawdę nie są takie rzeczy jako metody klasowe. Ponieważ wszystko jest obiektem w Ruby (włączając klasy), kiedy mówisz def self.class_method, tak naprawdę definiujesz pojedynczą metodę na instancji klasy Class. Tak więc, aby odpowiedzieć na twoje pytanie, jednoznaczne powiedzenie to jest dwa sposoby mówienia tego samego. Obie te metody są po prostu metodami singeton (eigen, meta, ghost lub cokolwiek chcesz je nazwać) zdefiniowanymi w instancji obiektu Class, który w twoim przykładzie był X. Ten temat jest częścią metaprogramowania, który jest zabawnym tematem, że jeśli używasz Ruby przez jakiś czas, powinieneś się przekonać. Pragmatyczni programiści mają świetny book na metaprogramming, który powinieneś koniecznie sprawdzić, jeśli jesteś zainteresowany tematem.

+2

Nie zgadzam się na temat "Nie ma czegoś takiego jak metoda klasy". Smalltalk istnieje już od dawna i jest również czystym OO i cały czas używa terminologii klasowej. Mówienie metodą klasową jest mniej mylące niż "singleton", ponieważ ta ostatnia jest wzorcem projektowym, a nie atrybutem języka. –

+1

Mogę dostać nagrodę za nekromancję tutaj, ale zdecydowanie zgadzam się z "nie ma czegoś takiego jak metoda klasy". Jeśli zdefiniujesz metodę na obiekcie eigenclass, a ten obiekt jest instancją 'Dog', nie wywołasz tej metody metodą psiarską. – ggPeti

+0

Jeśli oznaczysz metodę funkcją ': private_class_method', z pewnością spróbujesz, abyś pomyślał o niej jako o metodzie klasowej. –

3

Kolejny nekromanta, żeby wydobyć ten stary ... Jedno pytanie może nie być świadomy, że oznakowanie metody klasy jako private (używając słowa kluczowego prywatną zamiast :private_class_method) jest inna niż znakowania eigenclass metody jako takiej . :

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) 

Poniższy przykład będzie działać jak poprzedni zamierza:

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

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.