end
def ColoredRectangle.colored_square(r, g, b, s)
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
.
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'