Перейти к основному содержимому

Что это такое

Паттерн Visitor (Посетитель) добавляет новую операцию к семейству классов, не изменяя их. Классы один раз учатся одному — accept(visitor) — и с этого момента каждая новая операция это просто новый посетитель с одним методом на каждый класс.

Он переворачивает обычный компромисс: добавлять операции становится легко, а добавлять классы становится дорогим изменением.


Пример: операции над фигурами

Фигуры больше никогда не меняются. Печать площадей это один посетитель, печать названий другой — а завтрашний посетитель для экспорта в SVG не затронет ни Circle, ни Rectangle.

Новые операции, нетронутые классы

Оба посетителя проходят по одному и тому же массиву фигур через одну и ту же дверь accept: первый печатает площадь круга: 12.57 и площадь прямоугольника: 12.00, второй печатает два названия. Каждый посетитель хранит всю операцию в одном месте, вместо того чтобы разбрасывать её по классам.

Prompt
Напишите программу на TypeScript с паттерном Visitor: классы Circle и Rectangle с методом accept, интерфейс ShapeVisitor с методами visitCircle и visitRectangle, посетитель AreaPrinter, который печатает площадь каждой фигуры с двумя знаками после запятой, и посетитель NamePrinter, который печатает название каждой фигуры. Пройдите по массиву фигур обоими посетителями.
Вывод: программа на TypeScript и захваченный вывод

Когда его использовать

Используйте его, когда стабильное семейство классов постоянно обрастает новыми операциями — компиляторы обходят синтаксические деревья, документы получают экспортёры, фигуры получают отрисовщики и измерители.

Откажитесь от него, когда семейство всё ещё растёт: каждый новый класс вынуждает менять каждого посетителя. Во многих программах на TypeScript switch по размеченному объединению делает ту же работу с меньшим количеством механики — берите посетителя тогда, когда умножаются операции, а не классы.


Плюсы и минусы

Плюсы: целые операции живут каждая в своём классе; новые операции не требуют никаких изменений в посещаемых классах; связанная логика перестаёт быть разбросанной.

Минусы: двойная диспетчеризация (accept, вызывающий обратно) сбивает с толку новичков; добавление одного посещаемого класса означает правку каждого посетителя; интерфейс посещаемого семейства фиксируется рано.