Чтение онлайн

ЖАНРЫ

Программирование на языке Ruby
Шрифт:

MAX_SAMPLE =192

 def play

# ...

 end

end

def SoundPlayer.detect_hardware

 # ...

end

Единственная разница касается использования объявленных в классе констант. Если метод класса объявлен вне объявления самого класса, то эти константы оказываются вне области видимости. Например,

в первом фрагменте метод
detect_hardware
может напрямую обращаться к константе
MAX_SAMPLE
, а во втором придется пользоваться нотацией
SoundPlayer::MAX_SAMPLE
.

Не удивительно, что помимо методов класса есть еще и переменные класса. Их имена начинаются с двух знаков

@
, а областью видимости является весь класс, а не конкретный его экземпляр.

Традиционный пример использования переменных класса - подсчет числа его экземпляров. Но они могут применяться всегда, когда информации имеет смысл в контексте класса в целом, а не отдельного объекта. Другой пример приведен в листинге 11.3.

Листинг 11.3. Переменные и методы класса

class Metal

 @@current_temp = 70

 attr_accessor :atomic_number

 def Metal.current_temp=(x)

@@current_temp = x

 end

 def Metal.current_temp

@@current_temp

 end

 def liquid?

@@current_temp >= @melting

 end

 def initialize(atnum, melt)

@atomic_number = atnum

@melting = melt

 end

end

aluminum = Metal.new(13, 1236)

copper = Metal.new(29, 1982)

gold = Metal.new(79, 1948)

Metal.current_temp = 1600

puts aluminum.liquid? # true

puts copper.liquid? # false

puts gold.liquid? # false

Metal.current_temp = 2100

puts aluminum.liquid? # true

puts copper.liquid? # true

puts gold.liquid? # true

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

А если попытаться, что произойдет? Что если мы попробуем напечатать атрибут

@atomic_number
из метода
Metal.current_temp
? Обнаружится, что переменная вроде бы существует — никакой ошибки не возникает, — но имеет значение
nil
.
В чем дело?

В том, что на самом деле мы обращаемся вовсе не к переменной экземпляра класса

Metal
, а к переменной экземпляра класса
Class
. (Напомним, что в Ruby
Class
— это класс!)

Мы столкнулись с переменной экземпляра класса (термин заимствован из языка Smalltalk). Дополнительные замечания на эту тему приводятся в разделе 11.2.4.

В листинге 11.4 иллюстрируются все аспекты этой ситуации.

Листинг 11.4. Данные класса и экземпляра

class MyClass

 SOME_CONST = "alpha" # Константа уровня класса.

 @@var = "beta" # Переменная класса.

 @var = "gamma" # Переменная экземпляра класса.

 def initialize

@var = "delta" # Переменная экземпляра.

 end

 def mymethod

puts SOME_CONST # (Константа класса.)

puts @@var # (Переменная класса.)

puts @var # (Переменная экземпляра.)

 end

 def MyClass.classmeth1

puts SOME_CONST # (Константа класса.)

puts @@var # (Переменная класса.)

puts @var # (Переменная экземпляра класса.)

 end

end

def MyClass.classmeth2

 puts MyClass::SOME_CONST # (Константа класса.)

 # puts @@var # Ошибка: вне области видимости.

 puts @var # (Переменная экземпляра класса.)

end

myobj = MyClass.new

MyClass.classmeth1 # alpha, beta, gamma

MyClass.classmeth2 # alpha, gamma

myobj.mymethod # alpha, beta, delta

Следует еще сказать, что метод класса можно сделать закрытым, воспользовавшись методом

private_class_method
. Это аналог метода
private
на уровне экземпляра. См. также раздел 11.2.10.

11.1.5. Наследование суперклассу

Можно унаследовать класс, воспользовавшись символом

<
:

class Boojum < Snark

 # ...

end

Это объявление говорит, что класс

Boojum
является подклассом класса
Snark
или — что то же самое — класс
Snark
является суперклассом класса
Boojum
. Всем известно, что каждый буюм является снарком, но не каждый снарк — буюм.

Ясно, что цель наследования — расширить или специализировать функциональность. Мы хотим получить из общего нечто более специфическое.

Поделиться с друзьями: