🕵️
Введение в паттерны
  • Введение в паттерны
  • Паттерны
    • Оглавление
    • Порождающие паттерны
      • Фабричный метод
        • Реализации на С++
        • Реализации на Kotlin
        • Возможные реализации для решения конкретных задач на С++
      • Абстрактная фабрика
        • Реализации на С++
        • Реализации на Kotlin
        • Возможные реализации для решения конкретных задач на С++
      • Прототип
        • Реализации на С++
        • Реализации на Kotlin
        • Реализации на Java
        • Возможные реализации для решения конкретных задач на С++
      • Строитель
        • Реализации на С++
        • Реализации на Kotlin
      • Одиночка
        • Реализации на C++
        • Реализации на Kotlin
        • Возможные реализации для решения конкретных задач на С++
      • Пул объектов
        • Реализации на С++
    • Структурные паттерны
      • Адаптер
        • Реализации на С++
        • Реализации на Kotlin
        • Возможные реализации для решения конкретных задач
      • Декоратор
        • Реализации на С++
        • Реализации на Kotlin
      • Компоновщик
        • Реализации на С++
      • Мост
        • Реализации на С++
      • Заместитель
        • Реализации на С++
        • Реализации на Kotlin
      • Фасад
        • Реализации на С++
      • Приспособленец
        • Реализации на С++
    • Поведенческие паттерны
      • Стратегия
        • Реализации на С++
        • Реализации на Kotlin
      • Команда
        • Реализации на С++
        • Реализации на Kotlin
      • Цепочка обязанностей
        • Реализации на С++
        • Реализации на Kotlin
      • Подписчик-издатель
        • Реализации на С++
        • Реализации на Kotlin
      • Посетитель
        • Реализации на С++
        • Возможные реализации для решения конкретных задач
      • Посредник
        • Реализации на С++
        • Реализации на Kotlin
      • Шаблонный метод
        • Реализации на С++
      • Опекун
        • Реализации на С++
      • Итератор
        • Реализации на С++
        • Реализации на Kotlin
      • Свойство
        • Реализации на С++
        • Возможные реализации для решения конкретных задач
  • Введение в идиомы
  • Идиомы
    • Оглавление
    • RAII
    • Type erasure
      • Контейнеры с type erasure
    • CRTP
    • Статический полиморфизм
    • Shrink to fit
    • Proxy
    • Erase remove
    • Decltype (auto)
    • Copy and swap
    • Safe bool
    • Scope guard
    • Addressof
Powered by GitBook
On this page
  • Посетитель с приведением типа между базовыми классами
  • Посетитель с использованием шаблона variant ("безопасный" union)
  • Шаблонный посетитель (Template visitor) с использованием паттерна CRTP (Curiously Recurring Template Pattern)

Was this helpful?

  1. Паттерны
  2. Поведенческие паттерны
  3. Посетитель

Возможные реализации для решения конкретных задач

Visitor

Посетитель с приведением типа между базовыми классами

Реализация посетителя с приведением типа между базовыми классами использует пустой абстрактный класс посетителя, который дополняется посетителями конкретных типов при помощи реализации идиомы MixIn.

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

#include <iostream>
#include <vector>
#include <memory>

using namespace std;
class AbstractVisitor 
{
public:
    virtual ~AbstractVisitor() = default;
};
template <typename T>
class Visitor 
{
public:
    virtual ~Visitor() = default;
    virtual void visit(const T&) const = 0;
};
class Shape 
{
public:
    Shape() = default;
    virtual ~Shape() = default;
    virtual void accept(const AbstractVisitor&) const = 0;
};
class Circle : public Shape 
{
private:
    double radius;
public:
    Circle(double radius) : radius(radius) {}
    void accept(const AbstractVisitor& v) const override 
    {
        auto cv = dynamic_cast<const Visitor<Circle>*>(&v);
        if (cv)
            cv->visit(*this);
    }
};
class Square : public Shape 
{
private:
    double side;
public:
    Square(double side) : side(side) {}
    void accept(const AbstractVisitor& v) const override 
    {
        auto cv = dynamic_cast<const Visitor<Square>*>(&v);
        if (cv)
            cv->visit(*this);
    }
};
class DrawCircle : public Visitor<Circle> 
{
    void visit(const Circle& circle) const override 
    {
        cout << "Circle" << endl;
    }
};
class DrawSquare : public Visitor<Square> 
{
    void visit(const Square& circle) const override 
    {
        cout << "Square" << endl;
    }
};
class Figure : public Shape 
{
    using Shapes = vector<shared_ptr<Shape>>;
private:
    Shapes shapes;
public:
    Figure(initializer_list<shared_ptr<Shape>> list) 
    {
        for (auto&& elem : list)
            shapes.emplace_back(elem);
    }
    void accept(const AbstractVisitor& visitor) const override 
    {
        for (auto& elem : shapes)
            elem->accept(visitor);
    }
};
class Draw : public AbstractVisitor, public DrawCircle, public DrawSquare {};
int main() 
{
    shared_ptr<Shape> figure = make_shared<Figure>(
        initializer_list<shared_ptr<Shape>>(
            { make_shared<Circle>(1), make_shared<Square>(2) }
        )
    );
    figure->accept(Draw{});
}

Посетитель с использованием шаблона variant ("безопасный" union)

#include <iostream>
#include <vector>
#include <variant>

using namespace std;
class Circle {};
class Square {};
using Shape = std::variant<Circle, Square>;
class Formation
{
public:
    static vector<Shape> initialization(initializer_list<Shape> list)
    {
        vector<Shape> vec;
        for (auto&& elem : list)
            vec.emplace_back(elem);
        return vec;
    }
};
class Draw
{
public:
    void operator ()(const Circle&) const 
    { 
        cout << "Circle" << endl; 
    }
    void operator ()(const Square&) const 
    { 
        cout << "Square" << endl; 
    }
};
int main()
{
    using Shapes = vector<Shape>;
    Shapes fiqure = Formation::initialization({ Circle{}, Square{} });
    for (const auto& elem : fiqure)
        std::visit(Draw{}, elem);
}

Шаблонный посетитель (Template visitor) с использованием паттерна CRTP (Curiously Recurring Template Pattern)

Реализация шаблонного посетителя прибегает к вариативным шаблонам классов для определения типа посетителя, который посещает заданные классы. За счёт использования CRTP можно избавиться от реализации метода accept в каждой сущности, перенеся ответственность за это на класс Visitable.

# include <iostream>
# include <memory>
# include <initializer_list>
# include <vector>

using namespace std;
template <typename... Types>
class Visitor;

template <typename Type>
class Visitor<Type>
{
public:
    virtual void visit(Type& t) = 0;
};

template <typename Type, typename... Types>
class Visitor<Type, Types...> : public Visitor<Types...>
{
public:
    using Visitor<Types...>::visit;
    virtual void visit(Type& t) = 0;
};
using ShapeVisitor = Visitor<class Figure, class Camera>;
class Point {};
class Shape
{
public:
    Shape(const Point& pnt) : point(pnt) {}
    virtual ~Shape() = default;
    const Point& getPoint() const 
    { 
        return point; 
    }
    void setPoint(const Point& pnt) 
    { 
        point = pnt; 
    }
    virtual void accept(shared_ptr<ShapeVisitor> v) = 0;
private:
    Point point;
};
template <typename Derived>
class Visitable : public Shape
{
public:
    using Shape::Shape;
    void accept(shared_ptr<ShapeVisitor> v) override
    {
        v->visit(*static_cast<Derived*>(this));
    }
};
class Figure : public Visitable<Figure>
{
    using Visitable<Figure>::Visitable;
};
class Camera : public Visitable<Camera>
{
    using Visitable<Camera>::Visitable;
};
class Composite : public Shape
{
    using Shapes = vector<shared_ptr<Shape>>;
private:
    Shapes shapes{};
public:
    Composite(initializer_list<shared_ptr<Shape>> list) : Shape(Point{})
    {
        for (auto&& elem : list)
            shapes.emplace_back(elem);
    }
    void accept(shared_ptr<ShapeVisitor> visitor)  override
    {
        for (auto& elem : shapes)
            elem->accept(visitor);
    }
};
class DrawVisitor : public ShapeVisitor
{
public:
    void visit(Figure& fig) override 
    { 
        cout << "Draws a figure;" << endl; 
    }
    void visit(Camera& fig) override 
    { 
        cout << "Draws a camera;" << endl; 
    }
};
int main()
{
    Point p;
    shared_ptr<Composite> figure = make_shared<Composite>(
        initializer_list<shared_ptr<Shape>>(
            { make_shared<Figure>(p), make_shared<Camera>(p), make_shared<Figure>(p) }
        )
    );
    shared_ptr<ShapeVisitor> visitor = make_shared<DrawVisitor>();
    figure->accept(visitor);
}
PreviousРеализации на С++NextПосредник

Last updated 1 year ago

Was this helpful?