Иметь метод родительского класса доступ к константам подкласса - PullRequest
25 голосов
/ 26 января 2012

Например:

class Animal

 def make_noise
    print NOISE
 end

end

class Dog < Animal
    NOISE = "bark"
end

d = Dog.new
d.make_noise # I want this to print "bark" 

Как мне выполнить вышеуказанное?В настоящее время написано

uninitialized constant Animal::NOISE

Ответы [ 5 ]

27 голосов
/ 26 января 2012

Я думаю, что вы действительно не хотите постоянную;Я думаю, что вы хотите переменную экземпляра для класса:

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"

Однако, если вы уверены, что хотите постоянную:

class Animal
  def make_noise
    puts self.class::NOISE
    # or self.class.const_get(:NOISE)
  end
end
5 голосов
/ 02 мая 2013

один способ сделать это без переменных экземпляра класса:

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
0 голосов
/ 16 декабря 2016

Если вы делаете это для настройки своих подклассов так, чтобы базовый класс имел доступ к константам, то вы можете создать для них DSL следующим образом:

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

Этот способ немного более производительный, так как при каждом вызове метода вам не нужно анализировать класс для достижения обратной (или прямой?) Константы.

0 голосов
/ 12 октября 2014

Если вам нужен объектно-ориентированный путь (ТМ), то, я думаю, вы хотите:

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

Если вы хотите выполнить рефакторинг для предотвращения дублирования кода для 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 голосов
/ 26 января 2012

Я думаю, у вас неправильная концепция.Классы в Ruby похожи на классы в Java, Smalltalk, C #, ... и все являются шаблонами для своих экземпляров.Таким образом, класс определяет структуру и поведение его экземпляров, а также части структуры и поведения экземпляров его подклассов , но не наоборот .

Таким образом, прямой доступ из суперклассаконстанта в подклассе вообще невозможна, и это хорошо.Смотрите ниже, как это исправить.Для ваших классов определены следующие вещи:

  • class Animal определяет метод make_noise.
  • экземпляры class Animal могут вызывать метод make_noise.
  • class Dog определяет константу NOISE со своим значением.
  • экземпляры Dog, а сам класс Dog может использовать константу NOISE.

Что не возможно:

  • Экземпляры Animal или самого класса Animal имеют доступ к константам класса Dog.

Youможет исправить это следующим изменением:

class Animal
  def make_noise
    print Dog::NOISE
  end
end

Но это плохой стиль, потому что теперь ваш суперкласс (который является абстракцией о Dog и других животных) теперь знает что-то, что принадлежит Dog.

Лучшее решение было бы:

  1. Определить абстрактный метод в классе Animal, который определяет, что make_noise должно быть определено.Смотрите ответ https://stackoverflow.com/a/6792499/41540.
  2. Определяйте в ваших конкретных классах метод снова, но теперь со ссылкой на константу.
...