printПаттерны поведения

printПосетитель

Visitor

Назначение
Описывает операцию, выполняемую с каждым объектом из некоторой структуры. Паттерн посетитель позволяет определить новую операцию, не изменяя классы этих объектов.

Результаты
1. С помощью посетителей легко добавлять операции, зависящие от компонентов сложных объектов. Для определения новой операции над структурой объектов достаточно просто ввести нового посетителя.
2. Родственное поведение не разносится по всем классам, присутствующим в структуре объектов, оно локализовано в посетителе. Не связанные друг с другом функции распределяются по отдельным подклассам класса Visitor. Это способствует упрощению как классов, определяющих элементы, так и алгоритмов, инкапсулированных в посетителях. Все относящиеся к алгоритму структуры данных можно скрыть в посетителе.
3. Паттерн посетитель усложняет добавление новых подклассов класса Element. Каждый новый конкретный элемент требует объявления новой абстрактной операции в классе Visitor, которую нужно реализовать в каждом из существующих его подклассов. Поэтому при решении вопроса о том, стоит ли использовать паттерн посетитель, нужно прежде всего посмотреть, что будет изменяться чаще: алгоритм, применяемый к объектам структуры, или классы объектов, составляющих эту структуру. Паттерн посетитель следует применять в случае, если иерархия классов Element стабильна, но постоянно расширяется набор операций или модифицируются алгоритмы.
4. Итератор может посещать объекты структуры по мере ее обхода, вызывая операции объектов. Но итератор не способен работать со структурами, состоящими из объектов разных типов. У посетителя таких ограничений нет. Ему разрешено посещать объекты, не имеющие общего родительского класса.
5. Посетители могут аккумулировать информацию о состоянии при посещении объектов структуры. Если не использовать этот паттерн, состояние придется передавать в виде дополнительных аргументов операций, выполняющих обход, или хранить в глобальных переменных.
6. Применение посетителей подразумевает, что у элементов достаточно развитый интерфейс для того, чтобы посетители могли справиться со своей работой. Поэтому при использовании данного паттерна приходится предоставлять открытые операции для доступа к внутреннему состоянию элементов, что нарушает инкапсуляцию.

Реализация
class Visitor;
// Элемент определяет операцию Accept для приема посетителя
class Element {
public:
  virtual void Accept(Visitor &)=0;
};
// Конкретные элементы реализуют операцию Accept
class ElementA : public Element {
public:
  void Accept(Visitor &v) { v.Visit(*this); }
  void OperationA();
};
class ElementB : public Element {
public:
  void Accept(Visitor &v) { v.Visit(*this); }
  void OperationB();
};
// Посетитель объявляет операцию Visit для каждого подкласса Element
class Visitor {
public:
  virtual void Visit(ElementA &) {}
  virtual void Visit(ElementB &) {}
};
// Конкретный посетитель реализует нее операции, объявленные в классе Visitor
// Может содержать поля для накопления результатов в процессе обхода структуры
class Visitor1 : public Visitor {
public:
  void Visit(ElementA &e) {... e->OperationA(); ... }
  void Visit(ElementB &e) {... e->OperationB(); ... }
};
// Сложный объект предоставляет посетителю интерфейс для посещения своих элементов
class Object {
  vector<Element *> els;
public:
  void Accept(Visitor &v) 
  { for(size_t i=0;i<els.size();++i) 
      els[i]->Accept(v); 
  }
};
loading