Design patterns                
            Шаблон посетителя
        
        
            
    Поиск…
Пример шаблона посетителей в C ++
Вместо
struct IShape
{
    virtual ~IShape() = default;
    virtual void print() const = 0;
    virtual double area() const = 0;
    virtual double perimeter() const = 0;
    // .. and so on
};
Посетители могут быть использованы:
// The concrete shapes
struct Square;
struct Circle;
// The visitor interface
struct IShapeVisitor
{
    virtual ~IShapeVisitor() = default;
    virtual void visit(const Square&) = 0;
    virtual void visit(const Circle&) = 0;
};
// The shape interface
struct IShape
{
    virtual ~IShape() = default;
    virtual void accept(IShapeVisitor&) const = 0;
};
Теперь конкретные формы:
struct Point {
    double x;
    double y;
};
struct Circle : IShape
{
    Circle(const Point& center, double radius) : center(center), radius(radius) {}
    
    // Each shape has to implement this method the same way
    void accept(IShapeVisitor& visitor) const override { visitor.visit(*this); }
    Point center;
    double radius;
};
struct Square : IShape
{
    Square(const Point& topLeft, double sideLength) :
         topLeft(topLeft), sideLength(sideLength)
    {}
    // Each shape has to implement this method the same way
    void accept(IShapeVisitor& visitor) const override { visitor.visit(*this); }
    Point topLeft;
    double sideLength;
};
то посетители:
struct ShapePrinter : IShapeVisitor
{
    void visit(const Square&) override { std::cout << "Square"; }
    void visit(const Circle&) override { std::cout << "Circle"; }
};
struct ShapeAreaComputer : IShapeVisitor
{
    void visit(const Square& square) override
    {
        area = square.sideLength * square.sideLength;
    }
    void visit(const Circle& circle) override
    {
         area = M_PI * circle.radius * circle.radius;
    }
    double area = 0;
};
struct ShapePerimeterComputer : IShapeVisitor
{
    void visit(const Square& square) override { perimeter = 4. * square.sideLength; }
    void visit(const Circle& circle) override { perimeter = 2. * M_PI * circle.radius; }
    double perimeter = 0.;
};
И используйте его:
const Square square = {{-1., -1.}, 2.};
const Circle circle{{0., 0.}, 1.};
const IShape* shapes[2] = {&square, &circle};
ShapePrinter shapePrinter;
ShapeAreaComputer shapeAreaComputer;
ShapePerimeterComputer shapePerimeterComputer;
for (const auto* shape : shapes) {
    shape->accept(shapePrinter);
    std::cout << " has an area of ";
    // result will be stored in shapeAreaComputer.area
    shape->accept(shapeAreaComputer);
    // result will be stored in shapePerimeterComputer.perimeter
    shape->accept(shapePerimeterComputer); 
    std::cout << shapeAreaComputer.area
              << ", and a perimeter of "
              << shapePerimeterComputer.perimeter
              << std::endl;
}
Ожидаемый результат:
Square has an area of 4, and a perimeter of 8
Circle has an area of 3.14159, and a perimeter of 6.28319
Объяснение :
- В области - void Square::accept(IShapeVisitor& visitor) const override { visitor.visit(*this); }, статический тип- thisизвестен, и поэтому выбранная (во время компиляции) перегрузка- void IVisitor::visit(const Square&);,
- Для - square.accept(visitor);вызов, динамическая диспетчеризация через- virtualиспользуется для определения того, кто- acceptвызов.
Плюсы :
-  Вы можете добавить новую функциональность ( SerializeAsXml, ...) в классIShapeпросто добавив нового посетителя.
Минусы :
-  Добавление новой конкретной формы ( Triangle, ...) требует изменения всех посетителей.
 Альтернатива поместить все функции в качестве virtual методов в IShape имеет противоположные плюсы и минусы: добавление новой функциональности требует изменения всех существующих фигур, но добавление новой формы не влияет на существующие классы. 
Пример шаблона посетителя в java
 Шаблон Visitor позволяет добавлять новые операции или методы к набору классов без изменения структуры этих классов. 
Этот шаблон особенно полезен, если вы хотите централизовать определенную операцию над объектом без расширения объекта или без изменения объекта.
UML-диаграмма из Википедии:
Фрагмент кода:
import java.util.HashMap;
interface Visitable{
    void accept(Visitor visitor);
}
interface Visitor{
    void logGameStatistics(Chess chess);
    void logGameStatistics(Checkers checkers);
    void logGameStatistics(Ludo ludo);    
}
class GameVisitor implements Visitor{
    public void logGameStatistics(Chess chess){
        System.out.println("Logging Chess statistics: Game Completion duration, number of moves etc..");    
    }
    public void logGameStatistics(Checkers checkers){
        System.out.println("Logging Checkers statistics: Game Completion duration, remaining coins of loser");    
    }
    public void logGameStatistics(Ludo ludo){
        System.out.println("Logging Ludo statistics: Game Completion duration, remaining coins of loser");    
    }
}
abstract class Game{
    // Add game related attributes and methods here
    public Game(){
    
    }
    public void getNextMove(){};
    public void makeNextMove(){}
    public abstract String getName();
}
class Chess extends Game implements Visitable{
    public String getName(){
        return Chess.class.getName();
    }
    public void accept(Visitor visitor){
        visitor.logGameStatistics(this);
    }
}
class Checkers extends Game implements Visitable{
    public String getName(){
        return Checkers.class.getName();
    }
    public void accept(Visitor visitor){
        visitor.logGameStatistics(this);
    }
}
class Ludo extends Game implements Visitable{
    public String getName(){
        return Ludo.class.getName();
    }
    public void accept(Visitor visitor){
        visitor.logGameStatistics(this);
    }
}
public class VisitorPattern{
    public static void main(String args[]){
        Visitor visitor = new GameVisitor();
        Visitable games[] = { new Chess(),new Checkers(), new Ludo()};
        for (Visitable v : games){
            v.accept(visitor);
        }
    }
}
Объяснение:
-  Visitable(Element) - это интерфейс, и этот метод интерфейса должен быть добавлен к набору классов.
-  Visitor- это интерфейс, который содержит методы для выполнения операции над элементамиVisitable.
-  GameVisitor- это класс, который реализует интерфейсVisitor(ConcreteVisitor).
-  Каждый элемент VisitableпринимаетVisitorи вызывает соответствующий метод интерфейсаVisitor.
-  Вы можете рассматривать GameasElementи конкретные игры, такие какChess,Checkers and LudoкакConcreteElements.
 В приведенном выше примере Chess, Checkers and Ludo - это три разные игры (и классы Visitable ). В один прекрасный день я столкнулся со сценарием для регистрации статистики каждой игры. Поэтому, не изменяя индивидуальный класс для реализации функций статистики, вы можете централизовать эту ответственность в классе GameVisitor , что делает трюк для вас без изменения структуры каждой игры. 
выход:
Logging Chess statistics: Game Completion duration, number of moves etc..
Logging Checkers statistics: Game Completion duration, remaining coins of loser
Logging Ludo statistics: Game Completion duration, remaining coins of loser
Примеры использования / Применимость:
- Аналогичные операции должны выполняться на объектах разных типов, сгруппированных в структуру
- Вам нужно выполнить много разных и не связанных между собой операций. Он отделяет операцию от объектов. Структура
- Новые операции должны быть добавлены без изменения структуры объекта
- Собирайте связанные операции в один класс, а не заставляйте вас изменять или выводить классы
- Добавить функции в библиотеки классов, для которых у вас либо нет источника, либо невозможно изменить источник
Дополнительные ссылки:
Пример посетителя в C ++
// A simple class hierarchy that uses the visitor to add functionality.
//
class VehicleVisitor;
class Vehicle
{
    public:
        // To implement the visitor pattern
        // The class simply needs to implement the accept method 
        // That takes a reference to a visitor object that provides
        // new functionality.
        virtual void accept(VehicleVisitor& visitor) = 0
};
class Plane: public Vehicle
{
    public:
        // Each concrete representation simply calls the visit()
        // method on the visitor object passing itself as the parameter.
        virtual void accept(VehicleVisitor& visitor) {visitor.visit(*this);}
        void fly(std::string const& destination);
};
class Train: public Vehicle
{
    public:
        virtual void accept(VehicleVisitor& visitor) {visitor.visit(*this);}
        void locomote(std::string const& destination);
};
class Automobile: public Vehicle
{
    public:
        virtual void accept(VehicleVisitor& visitor) {visitor.visit(*this);}
        void drive(std::string const& destination);
};
class VehicleVisitor
{
    public:
        // The visitor interface implements one method for each class in the
        // hierarchy. When implementing new functionality you just create the
        // functionality required for each type in the appropriate method.
        virtual void visit(Plane& object)      = 0;
        virtual void visit(Train& object)      = 0;
        virtual void visit(Automobile& object) = 0;
    // Note: because each class in the hierarchy needs a virtual method
    // in visitor base class this makes extending the hierarchy ones defined
    // hard.
};
Пример использования:
// Add the functionality `Move` to an object via a visitor.
class MoveVehicleVisitor
{
    std::string const& destination;
    public:
        MoveVehicleVisitor(std::string const& destination)
            : destination(destination)
    {}
    virtual void visit(Plane& object)      {object.fly(destination);}
    virtual void visit(Train& object)      {object.locomote(destination);}
    virtual void visit(Automobile& object) {object.drive(destination);}
};
int main()
{
    MoveVehicleVisitor  moveToDenver("Denver");
    Vehicle&            object = getObjectToMove();
    object.accept(moveToDenver);
}
Перемещение больших объектов
Шаблон посетителя можно использовать для перемещения структур.
class GraphVisitor;
class Graph
{
    public:
        class Node
        {
            using Link = std::set<Node>::iterator;
            std::set<Link>   linkTo;
            public:
                void accept(GraphVisitor& visitor);
        };
        void accept(GraphVisitor& visitor);
    private:
        std::set<Node>  nodes;
};
class GraphVisitor
{
    std::set<Graph::Node*>  visited;
    public:
        void visit(Graph& graph)
        {
            visited.clear();
            doVisit(graph);
        } 
        bool visit(Graph::Node& node)
        {
            if (visited.find(&node) != visited.end()) {
                return false;
            }
            visited.insert(&node);
            doVisit(node);
            return true;
        }
    private: 
        virtual void doVisit(Graph& graph)      = 0;
        virtual void doVisit(Graph::Node& node) = 0;
};
void accept(GraphVisitor& visitor)
{
    // Pass the graph to the visitor.
    visitor.visit(*this);
    // Then do a depth first search of the graph.
    // In this situation it is the visitors responsibility
    // to keep track of visited nodes.
    for(auto& node: nodes) {
        node.accept(visitor);
    }
}
void Graph::Node::accept(GraphVisitor& visitor)
{
    // Tell the visitor it is working on a node and see if it was 
    // previously visited.
    if (visitor.visit(*this)) {
        // The pass the visitor to all the linked nodes.
        for(auto& link: linkTo) {
            link->accept(visitor);
        }
    }
}
