Відвідувач (шаблон проєктування)

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

Відвідувач дозволяє додавати нові віртуальні функції в родинні класи без зміни самих класів, натомість, один відвідувач створює клас, який реалізує всі відповідні спеціалізації віртуальної функції. Відвідувач приймає посилання на елемент й реалізується шляхом подвійної диспетчеризації.

Проблема, яку вирішує ред.

Над кожним об'єктом деякої структури виконується одна або більше операцій. Визначити нову операцію, не змінюючи класи об'єктів.

Випадки застосування ред.

Шаблон Відвідувач використовується, коли:

  • існує багато об'єктів різних класів з різними інтерфейсами, і потрібно виконати операцію над цими об'єктами, залежно від їх типу.
  • потрібно виконувати над об'єктами багато не пов'язаних між собою операцій, але не хочеться "забруднювати" цими операціями класи об'єктів. При цьому, якщо ці об'єкти використовуються у декількох проєктах, з'являється можливість включати операції лише в ті проєкти, де вони необхідні.
  • класи, які визначають структуру даних, змінюються рідко, але є потреба часто визначати нові операції над цією структурою. Якщо ж класи, які визначають структуру даних, змінюються часто, краще визначити операції в цих класах, адже при зміні інтерфейсів у класі даних необхідно змінювати і класи, які реалізують операції над цією структурою.
  • треба визначити операцію над деякою структурою, не змінюючи клас цієї структури.

Опис шаблону

Основним призначенням шаблону Відвідувач є введення абстрактної функціональності для сукупної ієрархічної структури об'єктів «елемент», а саме, шаблон Відвідувач дає змогу, не змінюючи класи елементів, додавати в них нові операції. Для цього вся обробна функціональність переноситься з самих класів елементів в ієрархію спадкування Відвідувача.

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

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


Реалізація ред.

Особливості шаблону ред.

Частини шаблону ред.

 
  • Відвідувач (зазвичай, абстрактний клас чи інтерфейс)
    • визначає дію над кожним класом конкретних елементів. Ім'я та сигнатура операції мають визначати конкретний клас даних, елемент якого треба відвідати. Це дає можливість відвідувачу доступатися до елементів через інтерфейс конкретного класу.
  • Конкретний відвідувач (конкретний клас, що наслідує Відвідувач)
    • реалізує чи перевизначає операції, визначені в базовому класі. Містить алгоритми, які виконуватимуться над об'єктами відповідного класу. Також даний клас утримує локальний стан алгоритмів (цей стан, зазвичай, утримує проміжні результати під час обходу структури, та ін.).
  • Елемент (зазвичай, абстрактний клас чи інтерфейс)
    • визначає операцію, яка приймає об'єкт відвідувача як аргумент.
  • Конкретний елемент (конкретний клас, що наслідує Елемент)
    • визначає операцію, що приймає об'єкт відвідувача як аргумент.
  • Структура елементів (клас, що реалізує структуру елементів)
    • може перераховувати елементи, які містить.
    • надає високорівневий інтерфейс, що дозволяє відвідувачу виконувати елементи.
    • може бути Компонувальником чи колекцією (як список або черга).

Взаємодія ред.

Файл:GoF, visitor diagram.png
  • Клієнт, що використовує Відвідувача, має створити об'єкт Конкретного відвідувача та обійти потрібні елементи, відвідуючи кожен з них цим об'єктом.
  • Коли елемент відвідується, він викликає операцію Відвідувача, що відповідає класу елементу. Елемент передає себе як аргумент в цю операцію щоб дозволити Відвідувачу доступ до його стану, якщо це необхідно.

Переваги ред.

  • спрощується додавання нових операцій;
  • об'єднання споріднених операції в класі Visitor;
  • клас Visitor може запам’ятовувати в собі якийсь стан під час обходу контейнера.

Недоліки ред.

  • важке додавання нових класів, оскільки потрібно оновлювати ієрархію відвідувачів.

Приклади реалізації ред.

C++ ред.

С# ред.

Java ред.

Див. також ред.

Посилання ред.