@Sword_Dancer

В чём суть шаблона проектирования Посетитель?

class MyClass1
{
    function accept(OperationGroup $operation) {$operation->visitMyClass1($this);}
    function method1() {}
    function method2() {}
}

abstract class OperationGroup {}
class OperationGroup1 extends OperationGroup
{
    function visitMyClass1(MyClass1 $myClass1) {$myClass1->method1(); /*.............*/ }
    function visitMyClass2(MyClass2 $myClass2) {$myClass2->method1(); /*.............*/ }
}

$myClass1 = new MyClass1();
$operationGroup1 = new OperationGroup1();

$myClass1->accept($operationGroup1);

Подскажите, пожалуйста, в чём суть шаблона проектирования Посетитель? Невзирая на все прочитанные статьи, всё равно непонятно. Методы visitMyClass1, visitMyClass2 и т.д. нужны, я так понимаю, для инкапсуляции работы с исходными классами MyClass1 и т.д., но зачем нужен метод accept в них?
Почему нельзя напрямую вызывать $operationGroup1->visitMyClass1($myClass1); ?
  • Вопрос задан
  • 197 просмотров
Решения вопроса 1
@oxidmod
Все дело в понимании когда стоит применять визитор. А применяют его тогда , когда нужно обойти дерево объектов неизвестной глубины. Простой пример - каталог товаров на сайте. Дерево категорий может содержать в себе подкатегории и товары. Подкатегории могут иметь неогрниченную вложенность. Задача - посчитать среднюю стоимость товара в категории.

Вложенными циклами не вариант, потому что неизвестно насколько вложены подкатегории. Рекусия уже лучше, но приведет к большому потреблению памяти и есть риск вылететь со стека. И вот тут к нам приходит Визитер

Теперь чтобы вам не нужно было сделать с деревом категорий-товаров - вам нужно только написать визитора который умеет работать с разными типами узлов этого дерева.

Еще пример - обычное окно приложения. На нем есть разные контролы, которые тоже образуют дерево. Само окно - это корневой елемент. В него вложены меню, рабочая область и статусная строка. В меню колекция подменюшек и в каждой подменю свое подменю или кнопки. В рабоей зоне могут быть разные области со своими контролами, и .т.д

Вам нужно обновлять состояние окна по определенным тригерам (например программа синканула свое состояние с облака и теперь нужно перерисовать количество входящих сообщений, нотификаций и тому подобное).
Если вы сделаете это жестко (захардкодите список елементов которые могут обновится, то вам будет трудно это поддерживать. При изменении этого списка (например контрол переехал из меню в статус бар или в соседнее меню или на несколько уровней вглубь) вам придется править код, которые находит нужный елемент в иерархии контролов. В случае визитора вам не важно где находится контрол. Всеравно будет обойдено все дерево. У каждого елемента есть метод accept, но каждый елемент вызывает нужный метод у визитора (кнопка - visitButton, лейба - visitLabel и.тд). Вам не нужно пилить гигантские свичи чтобы определить какой метод визитора вызвать напрямую. Вам не нужна рекурсия чтобы обойти все дерево. При появлении нового типа узла вы добавляете в визитор соответсвующий visit-метод и в классе представляющем этот елемент соотвествующий accept метод.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
KM-Brothers
@KM-Brothers
Я знаю, что ничего не знаю...
Посмотрите в книге "PHP. Объекты, шаблоны и методики программирования", страница 266.
Точно не помню, но так же должен быть хорошо рассмотрен данный шаблон в книге Мартина Фаулера.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы