2012-01-26 15 views

Odpowiedz

26

Myślę, że tak naprawdę nie chcesz stałej; Chyba, że ​​chcesz instancję zmiennej na klasy:

class Animal 
    @noise = "whaargarble" 
    class << self 
    attr_accessor :noise 
    end 
    def make_noise 
    puts self.class.noise 
    end 
end 

class Dog < Animal 
    @noise = "bark" 
end 

a = Animal.new 
d = Dog.new 
a.make_noise #=> "whaargarble" 
d.make_noise #=> "bark" 
Dog.noise = "WOOF" 
d.make_noise #=> "WOOF" 
a.make_noise #=> "whaargarble" 

Jednakże, jeśli jesteś pewien, że chcesz stała:

class Animal 
    def make_noise 
    puts self.class::NOISE 
    # or self.class.const_get(:NOISE) 
    end 
end 
+0

Ale jeśli używam zmiennej instancji, oznacza to, że każda instancja klasy Dog będzie musiała przechowywać dane o szumach, prawda? Hałas nie zmieni się między instancjami Psów (tj. Psy zawsze szczekają), dlatego właśnie pomyślałem o stałej podklasy. Co myślisz? – Tim

+0

@ Czas Nie, każda instancja klasy Dog nie przechowuje tej wartości. 'p Dog.new.instance_eval {@noise} # => nil' Pojedyncza instancja' Klasy' o nazwie 'Pies' przechowuje tę wartość. Podobnie jak instancje klas są obiektami, które mogą mieć zmienne instancji, więc same klasy są obiektami (instancjami klasy Class), które mogą mieć własne zmienne instancji. – Phrogz

+0

Zaktualizowałem przykład, aby pokazać, że są to właściwości samego "psa", a nie właściwości instancji Dog. Możesz nawet zmienić 'attr_accessor' na' attr_reader', jeśli chcesz mocniej wzmocnić jego stałość. – Phrogz

0

myślę, że masz złą koncepcję tutaj. Klasy w Ruby są podobne do klas w Javie, Smalltalk, C#, ... i wszystkie są szablonami dla ich instancji. Klasa definiuje więc strukturę i zachowanie, jeśli chodzi o instancje oraz części struktury i zachowanie wystąpień jej podklas. , ale nie wice versa.

Tak więc bezpośredni dostęp z nadklasy do stałej w podklasie nie jest w ogóle możliwy, a to dobrze. Zobacz poniżej, jak to naprawić. Dla klas zdefiniowanych, następujące rzeczy są prawdziwe:

  • class Animal definiuje metodę make_noise.
  • wystąpień class Animal może wywołać metodę make_noise.
  • class Dog definiuje stałą o wartości NOISE.
  • wystąpień Dog i sama klasa Dog może używać stałej NOISE.

Co nie jest możliwe:

  • Przypadki Animal lub klasa Animal sobie mieć dostęp do stałych klasy Dog.

można naprawić przez następujące zmiany:

class Animal 
    def make_noise 
    print Dog::NOISE 
    end 
end 

Ale to jest zły styl, bo teraz, twój nadklasą (co jest abstrakcją o Dog i inne zwierzęta) wie już coś, co należy do Dog.

Lepszym rozwiązaniem byłoby:

  1. zdefiniować sposób abstrakcyjny w klasie Animal, który określa, że ​​make_noise powinien być określony. Zobacz odpowiedź https://stackoverflow.com/a/6792499/41540.
  2. Zdefiniuj ponownie w swoich klasach konkretnych metodę, ale teraz w odniesieniu do stałej.
+0

W rzeczywistości jest to możliwe; zobacz moją odpowiedź. – Phrogz

+0

Widziałem twoją odpowiedź (potem), i to jest inne niż moje. Jest to fajna sztuczka, ale zły styl uzyskiwania dostępu do stałych podklas w superklasach ... – mliebelt

+0

Zgadzam się, że jest to rodzaj złego stylu i ogólnie nie krytykuję twojej odpowiedzi. Tylko w tym miejscu, w którym mówisz: "To, co chcesz osiągnąć, nie jest w ogóle możliwe". – Phrogz

4

jednym ze sposobów, aby to zrobić bez zmiennych instancji klasy:

class Animal 

def make_noise 
    print self.class::NOISE 
end 

end 

class Dog < Animal 
    NOISE = "bark" 
end 

d = Dog.new 
d.make_noise # prints bark 
-1

Jeśli chcesz mu obiektowy sposób (TM), to myślę, że chcesz:

class Animal 
    # abstract animals cannot make a noise 
end 

class Dog < Animal 
    def make_noise 
    print "bark" 
    end 
end 

class Cat < Animal 
    def make_noise 
    print "meow" 
    end 
end 

d = Dog.new 
d.make_noise # prints bark 

c = Cat.new 
c.make_noise # prints meow 

Jeśli chcesz zreaktować, aby zapobiec powieleniu kodu dla print:

class Animal 
    def make_noise 
    print noise 
    end 
end 

class Dog < Animal 
    def noise 
    "bark" 
    end 
end 

class Cat < Animal 
    def noise 
    if friendly 
     "meow" 
    else 
     "hiss" 
    end 
    end 
end 

d = Dog.new 
d.make_noise # prints bark 

c = Cat.new 
c.make_noise # prints meow or hiss 
0

Jeśli robisz to, aby skonfigurować sub klas tak, że klasa bazowa ma dostęp do stałych następnie można utworzyć DSL dla nich tak:

module KlassConfig 
    def attr_config(attribute) 
    define_singleton_method(attribute) do |*args| 
     method_name = "config_#{attribute}" 
     define_singleton_method method_name do 
     args.first 
     end 
     define_method method_name do 
     args.first 
     end 
    end 
    end 
end 

class Animal 
    extend KlassConfig 
    attr_config :noise 

    def make_noise 
    puts config_noise 
    end 
end 

class Dog < Animal 
    noise 'bark' 
end 

ten sposób jest nieco bardziej wydajnych jak na każdy wywołanie metody nie musisz introspekcji klasy, aby osiągnąć powrót (lub jest to forward?) dla stałej.

Powiązane problemy