Вход/Регистрация
Программирование на языке Ruby
вернуться

Фултон Хэл

Шрифт:

 def Terran.home_planet= (x)

@@home_planet = x

 end

 #...

end

Все замечательно, но что если нам нужно определить несколько подобных классов? Новичок подумает: «Ну так я просто определю суперкласс!» (листинг 11.12).

Листинг 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.

Листинг 11.13. Параметрические классы: улучшенное решение

class IntelligentLife

 def IntelligentLife.home_planet

class_eval("@@home_planet")

 end

 def IntelligentLife.home_planet=(x)

class_eval("@@home_planet = #{x}")

 end

 # ...

end

class Terran < IntelligentLife

 @@home_planet = "Earth"

 # ...

end

class Martian < IntelligentLife

 @@home_planet = "Mars"

 # ...

end

puts Terran.home_planet # Earth

puts Martian.home_planet # Mars

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

IntelligentLife
, наследуются классами
Terran
и
Martian
.

В листинге 11.14 предложено, наверное, наилучшее решение. В нем используются только переменные экземпляра, а от переменных класса мы вообще отказались.

Листинг 11.14. Параметрические классы: самое лучшее решение

class IntelligentLife

 class << self

attr_accessor :home_planet

 end

 # ...

end

class Terran < IntelligentLife

 self.home_planet = "Earth"

 #...

end

class Martian < IntelligentLife

 self.home_planet = "Mars"

 #...

end

puts Terran.home_planet # Earth

puts Martian.home_planet # Mars

Здесь мы открываем синглетный класс и определяем метод доступа

home_planet
. В двух подклассах определяются собственные методы доступа и устанавливается переменная. Теперь методы доступа работают строго в своих классах.

  • Читать дальше
  • 1
  • ...
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: