Что такое паттерн "Посетитель" (Visitor)
Посетитель — поведенческий паттерн проектирования, который позволяет добавлять новые операции к объектам без изменения их классов. Для этого используется отдельный объект — посетитель, который реализует нужные операции, а объекты принимают посетителя и вызывают соответствующие методы.
Представьте структуру объектов — например, элементы документа: текст, изображения, таблицы. Чтобы выполнить разные операции (например, подсчёт статистики, экспорт или рендеринг), можно создать разные посетители, не меняя классы элементов.
Преимущества паттерна «Посетитель»
- Позволяет добавлять новые операции без изменения существующих классов.
- Разделяет алгоритмы и структуру объектов.
- Упрощает поддержку и расширение функционала.
Пример:
- Интерфейс посетителя с методами для каждого типа элемента.
- Элементы с методом
accept(visitor)
, который вызывает метод посетителя.
Где применяется паттерн «Посетитель»?
- Компиляторы и парсеры.
- Обработка сложных структур данных (AST, DOM).
- Системы, где нужно выполнять разнообразные операции над объектами без изменения их классов.
Пример реализации на JavaScript
// Интерфейс посетителя class Visitor { visitText(element) { throw new Error("Метод visitText() должен быть реализован"); } visitImage(element) { throw new Error("Метод visitImage() должен быть реализован"); } } // Элементы с методом accept class TextElement { constructor(text) { this.text = text; } accept(visitor) { visitor.visitText(this); } } class ImageElement { constructor(url) { this.url = url; } accept(visitor) { visitor.visitImage(this); } } // Конкретный посетитель: подсчёт символов и изображений class CountVisitor extends Visitor { constructor() { super(); this.textCount = 0; this.imageCount = 0; } visitText(element) { this.textCount += element.text.length; } visitImage(element) { this.imageCount += 1; } } // Использование const elements = [ new TextElement("Привет"), new ImageElement("image1.png"), new TextElement("Мир"), ]; const visitor = new CountVisitor(); elements.forEach((el) => el.accept(visitor)); console.log(`Всего символов: ${visitor.textCount}`); console.log(`Всего изображений: ${visitor.imageCount}`);
Когда стоит использовать паттерн «Посетитель»?
- Когда нужно добавить новые операции, не изменяя классы объектов.
- При работе с сложными иерархиями объектов.
- Когда операции над объектами часто меняются, а классы — нет.
Отличие от других паттернов
- В отличие от Команды, где объект инкапсулирует действие, здесь посетитель инкапсулирует операцию над структурой.
- Отличается от Декоратора, который изменяет поведение объекта, а Посетитель добавляет новые операции.
Плюсы паттерна
- Позволяет легко расширять функциональность.
- Централизует операции над объектами.
- Упрощает добавление новых операций.
Минусы паттерна
- Сложно добавить новые типы элементов — нужно менять интерфейс посетителя и все его реализации.
- Может привести к усложнению кода из-за множества классов.