new(r, g, b, s, s)
end
def ColoredRectangle.red_square(s)
new(0xff, 0, 0, s, s)
end
def inspect
"#@r #@g #@b #@s1 #@s2"
end
end
a = ColoredRectangle.new(0x88, 0xaa, 0xff, 20, 30)
b = ColoredRectangle.white_rect(15,25)
с = ColoredRectangle.red_square(40)
Таким образом, можно определить любое число методов, создающих объекты по различным спецификациям. Вопрос о том, уместен ли здесь термин «конструктор», мы оставим «языковым адвокатам».
11.1.2. Создание атрибутов экземпляра
Имени атрибута экземпляра в Ruby всегда предшествует знак @
. Это обычная переменная в том смысле, что она начинает существовать после первого присваивания.
В ОО-языках часто создаются методы для доступа к атрибутам, чтобы обеспечить сокрытие данных. Мы хотим контролировать доступ к «внутренностям» объекта извне. Обычно для данной цели применяются методы чтения и установки (getter и setter), хотя в Ruby эта терминология не используется. Они просто читают (get) или устанавливают (set) значение атрибута.
Можно, конечно, запрограммировать такие функции «вручную», как показано ниже:
class Person
def name
@name
end
def name=(x)
@name = x
end
def age
@age
end
# ...
end
Ho Ruby предоставляет более короткий способ. Метод attr
принимает в качестве параметра символ и создает соответствующий атрибут. Кроме того, он создает одноименный метод чтения, а если необязательный второй параметр равен true, то и метод установки.
class Person
attr :name, true # Создаются @name, name, name=
attr :age # Создаются @age, age
end
Методы attr_reader
, attr_writer
и attr_accessor
принимают в качестве параметров произвольное число символов. Первый создает только «методы чтения» (для получения значения атрибута); второй — только «методы установки», а третий — то и другое. Пример:
class SomeClass
attr_reader :a1, :a2 # Создаются @a1, a1, @a2, a2
attr_writer :b1, :b2 # Создаются @b1, b1=, @b2, b2 =
attr_accessor :c1, :c2 # Создаются @c1, c1, c1=, @c2, c2, c2=
# ...
end
Напомним, что для выполнения присваивания атрибуту необходимо указывать вызывающий объект, а внутри метода нужно в качестве такого объекта указывать self
.
11.1.3. Более сложные конструкторы
По мере усложнения объектов у них появляется все больше атрибутов, которые необходимо инициализировать в момент создания. Соответствующий конструктор может оказаться длинным и запутанным, его параметры даже не будут помещаться на одной строке.
Чтобы справиться со сложностью, можно передать методу initialize
блок (листинг 11.2). Тогда инициализация объекта выполняется в процессе вычисле нияэтого блока. Хитрость в том, что вместо обычного eval
для вычисления блока в контексте объекта, а не вызывающей программы, следует использовать метод instance_eval
.
Листинг 11.2. «Хитрый» конструктор
class PersonalComputer
attr_accessor :manufacturer,
:model, :processor, :clock,
:ram, :disk, :monitor,
:colors, :vres, :hres, :net
def initialize(&block)
instance_eval &block
end
# Прочие методы...
end
desktop = PersonalComputer.new do
self.manufacturer = "Acme"
self.model = "THX-1138"
self.processor = "986"
self.clock = 9.6 # ГГц
self.ram =16 # Гб
self.disk =20 # T6
self.monitor = 25 # дюймы
self.colors = 16777216
self.vres = 1280
self.hres = 1600
self.net = "T3"
end
p desktop
Отметим несколько нюансов. Во-первых, мы пользуемся методами доступа к атрибутам, поэтому присваивание им значений интуитивно понятно. Во-вторых, ссылка на self
необходима, поскольку метод установки требует явного указания вызывающего объекта, чтобы можно было отличить вызов метода от обычного присваивания локальной переменной. Конечно, можно было не определять методы доступа, а воспользоваться функциями установки.
Ясно, что в теле блока можно делать все, что угодно. Например, можно было бы вычислить некоторые поля на основе других.
А если вам не нужны методы доступа для всех атрибутов? Если хотите, можете избавиться от лишних, вызвав для них метод undef
в конце конструирующего блока. Как минимум, это предотвратит «случайное» присваивание значения атрибуту извне объекта.
11.1.4. Создание атрибутов и методов уровня класса
Метод или атрибут не всегда ассоциируются с конкретным экземпляром класса, они могут принадлежать самому классу. Типичным примером метода класса может служить new
, он вызывается для создания новых экземпляров, а потому не может принадлежать никакому конкретному экземпляру.
Читать дальше
Конец ознакомительного отрывка
Купить книгу