← Назад ко всем вопросам

Что делает паттерн Visitor

1️⃣ Как кратко ответить

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

2️⃣ Подробное объяснение темы

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

Зачем нужен паттерн Visitor

  1. Разделение алгоритмов и структур данных: Visitor отделяет алгоритмы от структур данных, что упрощает добавление новых операций.
  2. Упрощение добавления новых операций: Вы можете добавлять новые операции, не изменяя классы объектов, что минимизирует риск внесения ошибок.
  3. Поддержка открытого/закрытого принципа: Позволяет добавлять новые функциональности без изменения существующего кода.

Как работает паттерн Visitor

Visitor работает путем создания интерфейса посетителя, который определяет метод для каждого типа элемента, который может быть посещен. Каждый класс элемента реализует метод accept, который принимает посетителя и вызывает соответствующий метод посетителя.

Пример кода

Рассмотрим пример, где у нас есть структура объектов, представляющая различные элементы документа: Paragraph и Image. Мы хотим добавить возможность их рендеринга и подсчета количества слов.

#include <iostream>
#include <vector>
#include <string>
​
// Интерфейс для всех элементов, которые могут быть посещены
class DocumentElement {
public:
    virtual ~DocumentElement() = default;
    virtual void accept(class Visitor &v) = 0;
};
​
// Конкретный элемент: Параграф
class Paragraph : public DocumentElement {
public:
    void accept(Visitor &v) override;
    std::string getText() const { return "This is a paragraph."; }
};
​
// Конкретный элемент: Изображение
class Image : public DocumentElement {
public:
    void accept(Visitor &v) override;
    std::string getPath() const { return "image.png"; }
};
​
// Интерфейс посетителя
class Visitor {
public:
    virtual void visit(Paragraph &p) = 0;
    virtual void visit(Image &i) = 0;
};
​
// Реализация метода accept для Paragraph
void Paragraph::accept(Visitor &v) {
    v.visit(*this);
}
​
// Реализация метода accept для Image
void Image::accept(Visitor &v) {
    v.visit(*this);
}
​
// Конкретный посетитель: Рендеринг
class RenderVisitor : public Visitor {
public:
    void visit(Paragraph &p) override {
        std::cout << "Rendering paragraph: " << p.getText() << std::endl;
    }
​
    void visit(Image &i) override {
        std::cout << "Rendering image from: " << i.getPath() << std::endl;
    }
};
​
// Конкретный посетитель: Подсчет слов
class WordCountVisitor : public Visitor {
public:
    void visit(Paragraph &p) override {
        // Пример подсчета слов в параграфе
        std::cout << "Word count in paragraph: " << 4 << std::endl; // Упрощенный подсчет
    }
​
    void visit(Image &i) override {
        // Изображения не содержат слов
        std::cout << "Word count in image: 0" << std::endl;
    }
};
​
int main() {
    std::vector<DocumentElement*> document = { new Paragraph(), new Image() };
​
    RenderVisitor renderVisitor;
    WordCountVisitor wordCountVisitor;
​
    for (auto element : document) {
        element->accept(renderVisitor);
        element->accept(wordCountVisitor);
    }
​
    for (auto element : document) {
        delete element;
    }
​
    return 0;
}

Объяснение кода

  • DocumentElement: Абстрактный базовый класс для всех элементов документа. Определяет метод accept, который принимает посетителя.
  • Paragraph и Image: Конкретные классы элементов, которые реализуют метод accept, вызывающий соответствующий метод посетителя.
  • Visitor: Интерфейс посетителя, определяющий методы visit для каждого типа элемента.
  • RenderVisitor и WordCountVisitor: Конкретные посетители, реализующие операции рендеринга и подсчета слов соответственно.
  • main: Создает вектор элементов документа и применяет к ним посетителей для выполнения операций.

Паттерн Visitor позволяет легко добавлять новые операции, такие как рендеринг и подсчет слов, без изменения классов Paragraph и Image. Это делает код более гибким и поддерживаемым.

Тема: Классы / ООП / Полиморфизм
Стадия: Tech

🔒 Подпишись на бусти автора и стань Алигатором, чтобы получить полный доступ к функционалу сайта и отслеживать свой прогресс!

Твои заметки