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

Что это такое

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

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


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

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

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

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

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

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

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

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


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

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

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