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

на главную - закладки

Жанры

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

Библиотека

delegate
предлагает три способа решения задачи. Класс
SimpleDelegator
полезен, когда объект, которому делегируется управление (делегат), может изменяться на протяжении времени жизни делегирующего объекта. Чтобы выбрать объект-делегат, используется метод
__setobj__
.

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

SimpleDelegator
не стану.

Метод верхнего уровня

DelegateClass
принимает в качестве параметра класс, которому делегируется управление. Затем он создает новый класс, которому мы можем унаследовать. Вот пример создания класса
Queue
, который делегирует объекту
Array
:

require 'delegate'

class MyQueue < DelegateClass(Array)

 def initialize(arg=[])

super(arg)

 end

 alias_method :enqueue, :push

 alias_method :dequeue, :shift

end

mq = MyQueue.new

mq.enqueue(123)

mq.enqueue(234)

p mq.dequeue # 123

p mq.dequeue # 234

Можно также унаследовать класс

Delegator
и реализовать метод
__getobj__
; именно таким образом реализован класс
SimpleDelegator
. При этом мы получаем больший контроль над делегированием.

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

forwardable
. Вернемся к примеру очереди:

require 'forwardable'

class MyQueue

 extend Forwardable

 def initialize(obj=[])

@queue = obj # Делегировать этому объекту.

 end

 def_delegator :@queue, :push, :enqueue

 def_delegator :@queue, :shift, :dequeue

 def_delegators :@queue, :clear, :empty?, :length, :size, :<<

 # Прочий код...

end

Как видно из этого примера, метод

def_delegator
ассоциирует вызов метода (скажем,
enqueue
) с объектом-делегатом
@queue
и одним из методов этого объекта (
push
).
Иными словами, когда мы вызываем метод
enqueue
для объекта
MyQueue
, производится делегирование методу push объекта
@queue
(который обычно является массивом).

Обратите внимание, мы пишем

:@queue
, а не
:queue
или
@queue
. Объясняется это тем, как написан класс
Forwardable
; можно было бы сделать и по-другому.

Иногда нужно делегировать методы одного объекта одноименным методам другого объекта. Метод

def_delegators
позволяет задать произвольное число таких методов. Например, в примере выше показано, что вызов метода
length
объекта
MyQueue
приводит к вызову метода
length
объекта
@queue
.

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

[]
или
[]=
для очереди; если вы так поступаете, то очередь перестает быть очередью.

Отметим еще, что показанный выше код позволяет вызывающей программе передавать объект конструктору (для использования в качестве объекта-делегата). В полном соответствии с духом «утилизации» это означает, что я могу выбирать вид объекта, которому делегируется управление, коль скоро он поддерживает те методы, которые вызываются в программе.

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

require 'thread'
.)

q1 = MyQueue.new # Используется любой массив.

q2 = MyQueue.new(my_array) # Используется конкретный массив.

q3 = MyQueue.new(Queue.new) # Используется Queue (thread.rb).

q4 = MyQueue.new(SizedQueue.new) # Используется SizedQueue (thread.rb).

Так, объекты

q3
и
q4
волшебным образом становятся безопасными относительно потоков, поскольку делегируют управление безопасному в этом отношении объекту (если, конечно, какой-нибудь не показанный здесь код не нарушит эту гарантию).

Существует также класс

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

Быть может, вы задумались о том, что лучше — делегирование или наследование. Но это неправильный вопрос. В некоторых ситуациях делегирование оказывается более подходящим решением. Предположим, к примеру, что имеется класс, у которого уже есть родитель. Унаследовать еще от одного родителя мы не можем (в Ruby множественное наследование запрещено), но делегирование в той или иной форме вполне допустимо.

11.2.10. Автоматическое определение методов чтения и установки на уровне класса

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

Темный мир

Алмазов Игорь
6. Жизнь Лекаря с нуля
Фантастика:
альтернативная история
аниме
попаданцы
5.00
рейтинг книги
Темный мир

Как я строил магическую империю 14

Зубов Константин
14. Как я строил магическую империю
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Как я строил магическую империю 14

Рассвет русского царства. Книга 2

Грехов Тимофей
2. Новая Русь
Фантастика:
альтернативная история
попаданцы
историческое фэнтези
5.00
рейтинг книги
Рассвет русского царства. Книга 2

Кондотьер

Листратов Валерий
7. Ушедший Род
Фантастика:
фэнтези
боевая фантастика
аниме
попаданцы
5.00
рейтинг книги
Кондотьер

Как я строил магическую империю 15

Зубов Константин
15. Как я строил магическую империю
Фантастика:
попаданцы
аниме
фантастика: прочее
5.00
рейтинг книги
Как я строил магическую империю 15

Законы Рода. Том 10

Мельник Андрей
10. Граф Берестьев
Фантастика:
юмористическая фантастика
аниме
фэнтези
5.00
рейтинг книги
Законы Рода. Том 10

Ларь

Билик Дмитрий Александрович
10. Бедовый
Фантастика:
городское фэнтези
мистика
5.75
рейтинг книги
Ларь

Александр Агренев. Трилогия

Кулаков Алексей Иванович
Александр Агренев
Фантастика:
альтернативная история
9.17
рейтинг книги
Александр Агренев. Трилогия

Законы Рода. Том 3

Мельник Андрей
3. Граф Берестьев
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Законы Рода. Том 3

Вторая волна

Сугралинов Данияр
3. Жатва душ
Фантастика:
социально-философская фантастика
постапокалипсис
рпг
5.00
рейтинг книги
Вторая волна

Законы Рода. Том 2

Мельник Андрей
2. Граф Берестьев
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Законы Рода. Том 2

Неудержимый. Книга XXXII

Боярский Андрей
32. Неудержимый
Фантастика:
аниме
фэнтези
фантастика: прочее
попаданцы
5.00
рейтинг книги
Неудержимый. Книга XXXII

Охотник на демонов

Шелег Дмитрий Витальевич
2. Живой лёд
Фантастика:
боевая фантастика
5.83
рейтинг книги
Охотник на демонов

Мастер 3

Чащин Валерий
3. Мастер
Фантастика:
героическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Мастер 3