Подтвердить что ты не робот

Попросите метод родительского класса получить доступ к константам подкласса

Например:

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
4b9b3361

Ответ 1

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

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

Ответ 2

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

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

Ответ 3

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

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

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

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

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

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

class Animal
  def make_noise
    print Dog::NOISE
  end
end

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

Лучшим решением будет:

  • Определить абстрактный метод в классе Animal, который определяет, что make_noise должен быть определен. См. Ответ fooobar.com/questions/142657/....
  • Определите в своих конкретных классах метод снова, но теперь со ссылкой на константу.

Ответ 4

Если вы делаете это для настройки ваших подклассов, чтобы базовый класс имел доступ к константам, вы можете создать 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

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

Ответ 5

Если вы хотите, чтобы Object-Oriented Way (TM), то я думаю, вы хотите:

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