logo
Программирование на языке Ruby

Листинг 11.12. Параметрические классы: неправильное решение

class IntelligentLife # Неправильный способ решения задачи!

 @@home_planet = nil

 def IntelligentLife.home_planet

  @@home _planet

 end

 def IntelligentLife.home_planet=(x)

  @@home_planet = x

 end

 #...

end

class Terran < IntelligentLife

 @@home_planet = "Earth"

 #...

end

class Martian < IntelligentLife

 @@home_planet = "Mars"

 #...

end

Но это работать не будет. Вызов Terran.home_planet напечатает не "Earth", а "Mars"! Почему так? Дело в том, что переменные класса — на практике не вполне переменные класса; они принадлежат не одному классу, а всей иерархии наследования. Переменная класса не копируется из родительского класса, а разделяется родителем (и, стало быть, со всеми братьями).

Можно было бы вынести определение переменной класса в базовый класс, но тогда перестали бы работать определенные нами методы класса! Можно было исправить и это, перенеся определения в дочерние классы, однако тем самым губится первоначальная идея, ведь таким образом объявляются отдельные классы без какой бы то ни было «параметризации».

Мы предлагаем другое решение. Отложим вычисление переменной класса до момента выполнения, воспользовавшись методом class_eval. Полное решение приведено в листинге 11.13.