Читати книгу - "Занурення в патерни проектування, Олександр Швець"
Шрифт:
Інтервал:
Додати в закладку:
Відвідувач описує спільний для всіх типів відвідувачів інтерфейс. Він оголошує набір методів, що відрізняються типом вхідного параметра. Кожному класу конкретних елементів повинен підходити свій метод. В мовах, які підтримують перевантаження методів, ці методи можуть мати однакові імена, але типи їхніх параметрів повинні відрізнятися.
Конкретні відвідувачі реалізують якусь особливу поведінку для всіх типів елементів, які можна подати через методи інтерфейсу відвідувача.
Елемент описує метод прийому відвідувача. Цей метод повинен мати лише один параметр, оголошений з типом загального інтерфейсу відвідувачів.
Конкретні елементи реалізують методи приймання відвідувача. Мета цього методу — викликати той метод відвідування, який відповідає типу цього елемента. Так відвідувач дізнається, з яким типом елементу він працює.
Клієнтом зазвичай виступає колекція або складний складовий об’єкт, наприклад, дерево Компонувальника. Здебільшого, клієнт не прив’язаний до конкретних класів елементів, працюючи з ними через загальний інтерфейс елементів.
ПсевдокодУ цьому прикладі Відвідувач додає до існуючої ієрархії класів геометричних фігур можливість експорту до XML.
Приклад організації експорту об’єктів XML через окремий клас-відвідувач.
// Складна ієрархія елементів.interface Shape is
method move(x, y)
method draw()
method accept(v: Visitor)
// Метод прийняття відвідувача повинен бути реалізований у
// кожному елементі, а не тільки у базовому класі. Це допоможе
// програмі визначити, який метод відвідувача потрібно викликати
// у випадку, якщо ви не знаєте тип елемента.
class Dot implements Shape is
// ...
method accept(v: Visitor) is
v.visitDot(this)
class Circle implements Shape is
// ...
method accept(v: Visitor) is
v.visitCircle(this)
class Rectangle implements Shape is
// ...
method accept(v: Visitor) is
v.visitRectangle(this)
class CompoundShape implements Shape is
// ...
method accept(v: Visitor) is
v.visitCompoundShape(this)
// Інтерфейс відвідувачів повинен містити методи відвідування
// кожного елемента. Важливо, щоб ієрархія елементів змінювалася
// рідко, оскільки при додаванні нового елемента доведеться
// змінювати всіх існуючих відвідувачів.
interface Visitor is
method visitDot(d: Dot)
method visitCircle(c: Circle)
method visitRectangle(r: Rectangle)
method visitCompoundShape(cs: CompoundShape)
// Конкретний відвідувач реалізує одну операцію для всієї
// ієрархії елементів. Нова операція = новий відвідувач.
// Відвідувача вигідно застосовувати, коли нові елементи
// додаються дуже зрідка, а нові операції — часто.
class XMLExportVisitor implements Visitor is
method visitDot(d: Dot) is
// Експорт id та координат центру точки.
method visitCircle(c: Circle) is
// Експорт id, координат центру та радіусу кола.
method visitRectangle(r: Rectangle) is
// Експорт id, координат лівого-верхнього кута, висоти
// та ширини прямокутника.
method visitCompoundShape(cs: CompoundShape) is
// Експорт id складової фігури, а також списку id
// підфігур, з яких вона складається.
// Програма може застосовувати відвідувача до будь-якого набору
// об'єктів елементів, навіть не уточнюючи їхні типи. Потрібний
// метод відвідувача буде обрано завдяки проходу через метод
// accept.
class Application is
field allShapes: array of Shapes
method export() is
exportVisitor = new XMLExportVisitor()
foreach (shape in allShapes) do
shape.accept(exportVisitor)
Вам не здається, що виклик методу accept — це зайва ланка? Якщо так, тоді ще раз рекомендую вам ознайомитися з проблемою раннього та пізнього зв’язування в статті Відвідувач і Double Dispatch.
ЗастосуванняЯкщо вам потрібно виконати якусь операцію над усіма елементами складної структури об’єктів, наприклад, деревом.
Відвідувач дозволяє застосовувати одну і ту саму операцію до об’єктів різних класів.
Якщо над об’єктами складної структури об’єктів потрібно виконувати деякі не пов’язані між собою операції, але ви не хочете «засмічувати» класи такими операціями.
Відвідувач дозволяє витягти споріднені операції з класів, що складають структуру об’єктів, помістивши їх до одного класу-відвідувача. Якщо структура об’єктів використовується в декількох програмах, то патерн дозволить кожній програмі мати тільки потрібні в ній операції.
Якщо нова поведінка має сенс тільки для деяких класів з існуючої ієрархії.
Відвідувач дозволяє визначити поведінку тільки для цих класів, залишивши її порожньою для всіх інших.
Кроки реалізаціїСтворіть інтерфейс відвідувача й оголосіть у ньому методи «відвідування» для кожного класу елемента, який існує в програмі.
Опишіть інтерфейс елементів. Якщо ви працюєте з уже існуючими класами, оголосіть абстрактний метод прийняття відвідувачів у базовому класі ієрархії елементів.
Реалізуйте методи прийняття в усіх конкретних елементах. Вони повинні переадресовувати виклики тому методу відвідувача, в якому тип параметра збігається з поточним класом елемента.
Ієрархія елементів повинна знати тільки про загальний інтерфейс відвідувачів. З іншого боку, відвідувачі знатимуть про всі класи елементів.
Для кожної нової поведінки створіть свій власний конкретний клас. Пристосуйте цю поведінку для роботи з усіма наявними типами елементів, реалізувавши всі методи інтерфейсу відвідувачів.
Ви можете зіткнутися з ситуацією, коли відвідувачу потрібен доступ до приватних полів елементів. У цьому випадку ви можете або розкрити доступ до цих полів, порушивши інкапсуляцію елементів, або зробити
Увага!
Сайт зберігає кукі вашого браузера. Ви зможете в будь-який момент зробити закладку та продовжити читання книги «Занурення в патерни проектування, Олександр Швець», після закриття браузера.