В качестве иллюстрации построим простую графическую систему. Предположим, что у
нас есть объект, который рисует линии и реагирует на единственное сообщение
drawFromTo(a, b, c, d). В качестве реакции на это сообщение рисуется отрезок сплошной
линии из точки с координатами (a,b) к точке с координатами (c,d).
Прежде всего мы построим перо, являющееся инструментом рисования, которое помнит
свои координаты. Объект-перо инкапсулирует две переменные, x и y, а также определяет
методы установки и сообщения этих переменных: getX(), getY(), setX(a), setY(b). Затем
объект-перо определяет два метода рисования — а именно, moveTo(a,b), который только
перемещает перо без рисования, и drawTo(a,b), который рисует линию. Эти методы могут
быть определены с помощью следующего псевдокода:
method moveTo(a, b)
self setX(a)
self setY(b)
end
method drawTo(a, b)
self drawFromTo(self getX(), self getY(), a, b)
self moveTo(a,b)
end
Объект-перо делегирует ответственность за метод drawFromTo объекту-линии (рис. 20.4).
Предположим, что программист хочет создать второе перо. Используя технику
делегирования, он прежде всего обеспечивает описание объекта, соотнося его (по
возможности) с уже существующими объектами. Одна из форм описания может
выглядеть так: «второе перо должно вести себя в точности как первое, но поддерживать
свои собственные координаты». Из этого описания ясно, что второе перо обязано
содержать свои собственные переменные и определять методы для setX и т. д. Однако
поскольку оно делегирует себя первому перу, это будут единственные методы, которые
надо определить; оставшиеся детали поведения будут унаследованы от первого пера.
Когда второму перу посылается сообщение, то получатель (второе перо) пересылается как
составная часть сообщения дальше по пути делегирования. Когда следующие сообщения
посылаются объекту self (клиенту в терминологии Либермана), поиск начинается снова с
исходного получателя. Тем самым сообщения setX и getX, — используемые, например, в
методе drawTo, будут сопоставляться с методами второго пера, а не первого. Этот процесс
сопоставления аналогичен способу, при котором связывание метода всегда начинается с
базового класса получателя. Проблемы, возникающие при этом способе, проявляются и в
своем «делегированном» эквиваленте.
Делегирующие объекты не всегда должны переопределять переменные. Предположим, мы
хотим создать калейдоскопическое перо, которое производит отражение относительно
осей x и y, рисуя четыре линии вместо одной линии для исходного пера (рис. 20.5). Мы
можем ввести объект, который переопределяет только метод drawTo; все остальное
поведение делегируется первоначальному перу. Поскольку координаты x и y являются
координатами исходного пера, изменения в пере типа «калейдоскоп» приводят к
изменениям в первоначальном пере. Новый метод drawTo выглядит следующим образом:
method drawTo(a, b)
self drawFromTo(self getX(), self getY(), a, b)
self drawFromTo(- self getX(), self getY(), — a, b)
self drawFromTo(self getX(), — self getY(), a, — b)
self drawFromTo(- self getX(), — self getY(), — a, — b)
self moveTo(a,b)
end
PDF created with pdfFactory Pro trial version www.pdffactory.com