Программирование на языке Ruby
Программирование на языке Ruby читать книгу онлайн
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
Однако мне этот способ представляется слишком примитивным. Поскольку я не думаю, что это существенно лучше, чем то же самое, сделанное вручную, задерживаться на классе
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
@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. Автоматическое определение методов чтения и установки на уровне класса
Мы уже рассматривали методы
attr_reader
attr_writer
attr_accessor
В Ruby нет аналогичных средств для их автоматического создания. Но можно написать нечто подобное самостоятельно.
В первом издании этой книги была показана хитроумная схема на основе метода
class_eval
cattr_reader
cattr_writer
Но есть более простой путь. Откроем синглетный класс и воспользуемся в нем семейством методов
attr