Skip to main content

Як Visitor допомагає додавати нові операції без зміни класів?

Патерн Visitor (Відвідувач) дозволяє додавати нові операції над об'єктами без зміни їхніх класів, тому що вся логіка нових дій виноситься у зовнішній об'єкт - відвідувача.


1. Проблема без Visitor

Припустімо, є декілька типів елементів:

java
class Circle { void draw() { ... } } class Square { void draw() { ... } }

Тепер потрібно додати нові операції:

  • експорт у PDF,
  • розрахунок площі,
  • валідація параметрів.

Без Visitor довелося б у кожен клас додавати нові методи:

java
class Circle { void draw() { ... } void exportToPDF() { ... } // додали void calculateArea() { ... } // додали }

Проблеми:

  • щоразу доводиться редагувати наявні класи;
  • при десятках операцій і елементів код швидко розростається;
  • порушується принцип Open/Closed (класи відкриті для модифікацій).

2. Як це вирішує Visitor

Visitor виносить усі "дії" з самих класів у зовнішні об'єкти - відвідувачів. Тепер кожен новий алгоритм створюється у вигляді нового класу, а не як нові методи всередині елементів.


3. Структура

java
interface Shape { void accept(ShapeVisitor visitor); } interface ShapeVisitor { void visit(Circle c); void visit(Square s); } class Circle implements Shape { public void accept(ShapeVisitor visitor) { visitor.visit(this); } } class Square implements Shape { public void accept(ShapeVisitor visitor) { visitor.visit(this); } }

4. Додавання нових операцій

Щоб додати, наприклад, експорт у PDF, потрібно просто створити нового відвідувача:

java
class ExportToPDFVisitor implements ShapeVisitor { public void visit(Circle c) { System.out.println("Експорт кола в PDF"); } public void visit(Square s) { System.out.println("Експорт квадрата в PDF"); } }

Для іншої операції (наприклад, підрахунок площі) - інший відвідувач:

java
class AreaCalculationVisitor implements ShapeVisitor { public void visit(Circle c) { System.out.println("Обчислення площі кола"); } public void visit(Square s) { System.out.println("Обчислення площі квадрата"); } }

Елементи (Circle, Square) залишаються незмінними - вони просто "приймають" відвідувача.


5. Використання

java
List<Shape> shapes = List.of(new Circle(), new Square()); // Додаємо будь-яку нову операцію без зміни Shape-класів ShapeVisitor exportVisitor = new ExportToPDFVisitor(); ShapeVisitor areaVisitor = new AreaCalculationVisitor(); for (Shape shape : shapes) { shape.accept(exportVisitor); shape.accept(areaVisitor); }

6. Чому це працює

  • Елементи знають лише, як прийняти відвідувача (accept()), але не знають, що він з ними робить.
  • Відвідувач реалізує всі конкретні операції для кожного типу елемента.
  • Додавання нової операції = новий Visitor, без торкання Shape, Circle, Square.

7. Принцип, що реалізується

Visitor втілює принцип Open/Closed:

Класи елементів закриті для модифікації, але відкриті для розширення через нових відвідувачів.


Висновок

Visitor дозволяє додавати нові операції, не змінюючи класи самих об'єктів, тому що:

  1. Уся логіка нових дій винесена в зовнішні класи (відвідувачів).
  2. Елементи лише надають точку входу - метод accept().
  3. Додавання нової поведінки = створення нового відвідувача, а не зміна наявних класів.

Підсумок:

Visitor переносить зміни зсередини класів у зовнішній шар поведінки, зберігаючи стабільність структури і гнучкість системи.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.