第二十章:遍历万象,操作随心——Visitor的访问艺术

第二十章:遍历万象,操作随心------Visitor的访问艺术

风云再起,访问学者登场

在State展示完他那精妙的状态艺术后,Visitor彬彬有礼地走出,向复杂的对象结构行礼。他的举止优雅从容,仿佛一位学识渊博的学者在审视着精密的学术体系。

"State兄的状态管理确实精妙,"Visitor优雅地说道,"但在不修改现有对象结构的前提下定义新操作方面,需要更加灵活的访问方式。诸位请看------"

Visitor的身形在几个不同的对象结构间穿梭,却始终保持着适当的距离:"我的访问者模式,专为解决算法与对象结构分离问题而生!我允许你在不修改现有对象结构的前提下,定义作用于这些元素的新操作!"

架构老人眼中闪过赞许之色:"善!Visitor,就请你为大家展示这访问艺术的精妙所在。"

访问者模式的核心要义

Visitor面向众人,开始阐述他的武学真谛:

"在我的访问者模式中,主要包含两个核心角色:"

"Visitor(访问者):为对象结构中的每个ConcreteElement类声明一个Visit操作。"

"ConcreteVisitor(具体访问者):实现每个由Visitor声明的操作。"

"Element(元素):定义一个Accept操作,它以一个访问者为参数。"

"ConcreteElement(具体元素):实现Accept操作。"

"其精妙之处在于,"Visitor继续道,"我将算法与对象结构分离,使得可以在不修改现有元素类的情况下增加新的操作。访问者可以累积状态,将有关状态存储在其内部!"

C++实战:文档处理系统

"且让我以一个文档处理系统为例,展示访问者模式的实战应用。"Visitor说着,手中凝聚出一道道代码流光。

基础框架搭建

首先,Visitor定义了文档元素和访问者接口:

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
#include <memory>
#include <algorithm>
#include <map>
#include <iomanip>
#include <sstream>
#include <random>
#include <thread>
#include <chrono>

// 前向声明
class TextElement;
class ImageElement;
class TableElement;
class ParagraphElement;

// 访问者接口
class DocumentVisitor {
public:
    virtual ~DocumentVisitor() = default;
    
    // 访问各种文档元素的方法
    virtual void visit(TextElement* element) = 0;
    virtual void visit(ImageElement* element) = 0;
    virtual void visit(TableElement* element) = 0;
    virtual void visit(ParagraphElement* element) = 0;
    
    // 访问者信息
    virtual std::string getVisitorName() const = 0;
    virtual std::string getDescription() const = 0;
    
    // 访问者状态管理
    virtual void reset() = 0;
    virtual std::string getResults() const = 0;
};

// 文档元素接口
class DocumentElement {
public:
    virtual ~DocumentElement() = default;
    
    // 接受访问者访问
    virtual void accept(DocumentVisitor* visitor) = 0;
    
    // 元素基本信息
    virtual std::string getElementType() const = 0;
    virtual std::string getId() const = 0;
    virtual int getSize() const = 0; // 估算大小
    virtual std::string getContentPreview() const = 0;
    
    // 元素位置信息
    virtual void setPosition(int x, int y) = 0;
    virtual std::pair<int, int> getPosition() const = 0;
    
    // 元素样式
    virtual void setStyle(const std::string& style) = 0;
    virtual std::string getStyle() const = 0;
};

具体元素实现

Visitor展示了各种文档元素的具体实现:

cpp 复制代码
// 具体元素:文本元素
class TextElement : public DocumentElement {
private:
    std::string id_;
    std::string content_;
    std::pair<int, int> position_;
    std::string style_;
    int fontSize_;
    std::string fontFamily_;
    
public:
    TextElement(const std::string& id, const std::string& content, 
                int x = 0, int y = 0, const std::string& style = "normal")
        : id_(id), content_(content), position_({x, y}), style_(style),
          fontSize_(12), fontFamily_("Arial") {
        std::cout << "📝 创建文本元素: " << id_ << std::endl;
    }
    
    void accept(DocumentVisitor* visitor) override {
        visitor->visit(this);
    }
    
    std::string getElementType() const override { return "Text"; }
    std::string getId() const override { return id_; }
    
    int getSize() const override {
        return content_.length() * 2; // 估算大小
    }
    
    std::string getContentPreview() const override {
        std::string preview = content_;
        if (preview.length() > 20) {
            preview = preview.substr(0, 17) + "...";
        }
        return "文本: \"" + preview + "\"";
    }
    
    void setPosition(int x, int y) override {
        position_ = {x, y};
    }
    
    std::pair<int, int> getPosition() const override {
        return position_;
    }
    
    void setStyle(const std::string& style) override {
        style_ = style;
    }
    
    std::string getStyle() const override {
        return style_;
    }
    
    // 文本元素特有方法
    std::string getContent() const { return content_; }
    void setContent(const std::string& content) { content_ = content; }
    
    int getFontSize() const { return fontSize_; }
    void setFontSize(int size) { fontSize_ = size; }
    
    std::string getFontFamily() const { return fontFamily_; }
    void setFontFamily(const std::string& font) { fontFamily_ = font; }
    
    int getWordCount() const {
        std::istringstream iss(content_);
        return std::distance(std::istream_iterator<std::string>(iss), 
                            std::istream_iterator<std::string>());
    }
    
    std::string getDetailedInfo() const {
        std::stringstream ss;
        ss << "文本元素[" << id_ << "] 位置:(" << position_.first << "," << position_.second 
           << ") 字数:" << getWordCount() << " 样式:" << style_;
        return ss.str();
    }
};

// 具体元素:图片元素
class ImageElement : public DocumentElement {
private:
    std::string id_;
    std::string imagePath_;
    std::pair<int, int> position_;
    std::string style_;
    int width_;
    int height_;
    std::string format_;
    double fileSizeMB_;
    
public:
    ImageElement(const std::string& id, const std::string& path, 
                 int width = 100, int height = 100, double fileSize = 1.0)
        : id_(id), imagePath_(path), position_({0, 0}), style_("normal"),
          width_(width), height_(height), format_("JPEG"), fileSizeMB_(fileSize) {
        std::cout << "🖼️  创建图片元素: " << id_ << std::endl;
    }
    
    void accept(DocumentVisitor* visitor) override {
        visitor->visit(this);
    }
    
    std::string getElementType() const override { return "Image"; }
    std::string getId() const override { return id_; }
    
    int getSize() const override {
        return static_cast<int>(fileSizeMB_ * 1024); // KB
    }
    
    std::string getContentPreview() const override {
        return "图片: " + imagePath_ + " [" + std::to_string(width_) + "x" + 
               std::to_string(height_) + "]";
    }
    
    void setPosition(int x, int y) override {
        position_ = {x, y};
    }
    
    std::pair<int, int> getPosition() const override {
        return position_;
    }
    
    void setStyle(const std::string& style) override {
        style_ = style;
    }
    
    std::string getStyle() const override {
        return style_;
    }
    
    // 图片元素特有方法
    std::string getImagePath() const { return imagePath_; }
    void setImagePath(const std::string& path) { imagePath_ = path; }
    
    int getWidth() const { return width_; }
    void setWidth(int width) { width_ = width; }
    
    int getHeight() const { return height_; }
    void setHeight(int height) { height_ = height; }
    
    std::string getFormat() const { return format_; }
    void setFormat(const std::string& format) { format_ = format; }
    
    double getFileSizeMB() const { return fileSizeMB_; }
    void setFileSizeMB(double size) { fileSizeMB_ = size; }
    
    double getAspectRatio() const {
        return static_cast<double>(width_) / height_;
    }
    
    std::string getDetailedInfo() const {
        std::stringstream ss;
        ss << "图片元素[" << id_ << "] 路径:" << imagePath_ 
           << " 尺寸:" << width_ << "x" << height_ 
           << " 大小:" << std::fixed << std::setprecision(2) << fileSizeMB_ << "MB";
        return ss.str();
    }
};

// 具体元素:表格元素
class TableElement : public DocumentElement {
private:
    std::string id_;
    std::vector<std::vector<std::string>> data_;
    std::pair<int, int> position_;
    std::string style_;
    int rows_;
    int columns_;
    std::string title_;
    
public:
    TableElement(const std::string& id, int rows = 3, int columns = 3, 
                 const std::string& title = "")
        : id_(id), position_({0, 0}), style_("normal"), 
          rows_(rows), columns_(columns), title_(title) {
        
        // 初始化表格数据
        data_.resize(rows);
        for (int i = 0; i < rows; ++i) {
            data_[i].resize(columns);
            for (int j = 0; j < columns; ++j) {
                data_[i][j] = "Cell(" + std::to_string(i) + "," + std::to_string(j) + ")";
            }
        }
        
        std::cout << "📊 创建表格元素: " << id_ << " [" << rows_ << "x" << columns_ << "]" << std::endl;
    }
    
    void accept(DocumentVisitor* visitor) override {
        visitor->visit(this);
    }
    
    std::string getElementType() const override { return "Table"; }
    std::string getId() const override { return id_; }
    
    int getSize() const override {
        int totalChars = 0;
        for (const auto& row : data_) {
            for (const auto& cell : row) {
                totalChars += cell.length();
            }
        }
        return totalChars;
    }
    
    std::string getContentPreview() const override {
        return "表格: " + title_ + " [" + std::to_string(rows_) + "x" + 
               std::to_string(columns_) + "]";
    }
    
    void setPosition(int x, int y) override {
        position_ = {x, y};
    }
    
    std::pair<int, int> getPosition() const override {
        return position_;
    }
    
    void setStyle(const std::string& style) override {
        style_ = style;
    }
    
    std::string getStyle() const override {
        return style_;
    }
    
    // 表格元素特有方法
    void setCell(int row, int col, const std::string& value) {
        if (row >= 0 && row < rows_ && col >= 0 && col < columns_) {
            data_[row][col] = value;
        }
    }
    
    std::string getCell(int row, int col) const {
        if (row >= 0 && row < rows_ && col >= 0 && col < columns_) {
            return data_[row][col];
        }
        return "";
    }
    
    int getRowCount() const { return rows_; }
    int getColumnCount() const { return columns_; }
    
    std::string getTitle() const { return title_; }
    void setTitle(const std::string& title) { title_ = title; }
    
    int getTotalCells() const {
        return rows_ * columns_;
    }
    
    std::string getDetailedInfo() const {
        std::stringstream ss;
        ss << "表格元素[" << id_ << "] 标题:" << title_ 
           << " 尺寸:" << rows_ << "x" << columns_ 
           << " 总单元格:" << getTotalCells();
        return ss.str();
    }
};

// 具体元素:段落元素
class ParagraphElement : public DocumentElement {
private:
    std::string id_;
    std::vector<std::shared_ptr<DocumentElement>> children_;
    std::pair<int, int> position_;
    std::string style_;
    std::string alignment_;
    int lineSpacing_;
    
public:
    ParagraphElement(const std::string& id, const std::string& alignment = "left")
        : id_(id), position_({0, 0}), style_("normal"), 
          alignment_(alignment), lineSpacing_(1) {
        std::cout << "📄 创建段落元素: " << id_ << std::endl;
    }
    
    void accept(DocumentVisitor* visitor) override {
        visitor->visit(this);
        
        // 让访问者访问所有子元素
        for (auto& child : children_) {
            child->accept(visitor);
        }
    }
    
    std::string getElementType() const override { return "Paragraph"; }
    std::string getId() const override { return id_; }
    
    int getSize() const override {
        int totalSize = 0;
        for (const auto& child : children_) {
            totalSize += child->getSize();
        }
        return totalSize;
    }
    
    std::string getContentPreview() const override {
        return "段落: " + std::to_string(children_.size()) + " 个子元素";
    }
    
    void setPosition(int x, int y) override {
        position_ = {x, y};
    }
    
    std::pair<int, int> getPosition() const override {
        return position_;
    }
    
    void setStyle(const std::string& style) override {
        style_ = style;
    }
    
    std::string getStyle() const override {
        return style_;
    }
    
    // 段落元素特有方法
    void addChild(std::shared_ptr<DocumentElement> child) {
        children_.push_back(child);
    }
    
    void removeChild(const std::string& childId) {
        children_.erase(
            std::remove_if(children_.begin(), children_.end(),
                [&childId](const std::shared_ptr<DocumentElement>& child) {
                    return child->getId() == childId;
                }),
            children_.end()
        );
    }
    
    std::vector<std::shared_ptr<DocumentElement>> getChildren() const {
        return children_;
    }
    
    std::string getAlignment() const { return alignment_; }
    void setAlignment(const std::string& alignment) { alignment_ = alignment; }
    
    int getLineSpacing() const { return lineSpacing_; }
    void setLineSpacing(int spacing) { lineSpacing_ = spacing; }
    
    int getChildCount() const {
        return children_.size();
    }
    
    std::string getDetailedInfo() const {
        std::stringstream ss;
        ss << "段落元素[" << id_ << "] 子元素数:" << getChildCount() 
           << " 对齐:" << alignment_ << " 行距:" << lineSpacing_;
        return ss.str();
    }
};

具体访问者实现

Visitor展示了各种文档处理操作的具体实现:

cpp 复制代码
// 具体访问者:文档统计访问者
class DocumentStatsVisitor : public DocumentVisitor {
private:
    int textCount_;
    int imageCount_;
    int tableCount_;
    int paragraphCount_;
    int totalSize_;
    int totalWords_;
    std::vector<std::string> visitedElements_;
    
public:
    DocumentStatsVisitor() 
        : textCount_(0), imageCount_(0), tableCount_(0), paragraphCount_(0),
          totalSize_(0), totalWords_(0) {
        std::cout << "📊 创建文档统计访问者" << std::endl;
    }
    
    void visit(TextElement* element) override {
        textCount_++;
        totalSize_ += element->getSize();
        totalWords_ += element->getWordCount();
        visitedElements_.push_back("文本: " + element->getId());
        
        std::cout << "   📝 统计文本: " << element->getId() 
                  << " (字数:" << element->getWordCount() << ")" << std::endl;
    }
    
    void visit(ImageElement* element) override {
        imageCount_++;
        totalSize_ += element->getSize();
        visitedElements_.push_back("图片: " + element->getId());
        
        std::cout << "   🖼️  统计图片: " << element->getId() 
                  << " (大小:" << std::fixed << std::setprecision(2) 
                  << element->getFileSizeMB() << "MB)" << std::endl;
    }
    
    void visit(TableElement* element) override {
        tableCount_++;
        totalSize_ += element->getSize();
        visitedElements_.push_back("表格: " + element->getId());
        
        std::cout << "   📊 统计表格: " << element->getId() 
                  << " (单元格:" << element->getTotalCells() << ")" << std::endl;
    }
    
    void visit(ParagraphElement* element) override {
        paragraphCount_++;
        visitedElements_.push_back("段落: " + element->getId());
        
        std::cout << "   📄 统计段落: " << element->getId() 
                  << " (子元素:" << element->getChildCount() << ")" << std::endl;
    }
    
    std::string getVisitorName() const override {
        return "文档统计访问者";
    }
    
    std::string getDescription() const override {
        return "统计文档中各种元素的数量和大小";
    }
    
    void reset() override {
        textCount_ = imageCount_ = tableCount_ = paragraphCount_ = 0;
        totalSize_ = totalWords_ = 0;
        visitedElements_.clear();
        std::cout << "🔄 重置文档统计" << std::endl;
    }
    
    std::string getResults() const override {
        std::stringstream ss;
        ss << "📊 文档统计结果:" << std::endl;
        ss << "   文本元素: " << textCount_ << " 个" << std::endl;
        ss << "   图片元素: " << imageCount_ << " 个" << std::endl;
        ss << "   表格元素: " << tableCount_ << " 个" << std::endl;
        ss << "   段落元素: " << paragraphCount_ << " 个" << std::endl;
        ss << "   总字数: " << totalWords_ << " 个" << std::endl;
        ss << "   总大小: " << totalSize_ << " 单位" << std::endl;
        ss << "   访问元素总数: " << visitedElements_.size() << " 个" << std::endl;
        
        return ss.str();
    }
    
    // 统计访问者特有方法
    void showDetailedStats() const {
        std::cout << "\n📈 详细统计信息:" << std::endl;
        std::cout << getResults();
        
        std::cout << "\n📋 访问的元素列表:" << std::endl;
        for (size_t i = 0; i < visitedElements_.size(); ++i) {
            std::cout << "   " << (i + 1) << ". " << visitedElements_[i] << std::endl;
        }
    }
    
    double getAverageWordsPerText() const {
        return textCount_ > 0 ? static_cast<double>(totalWords_) / textCount_ : 0.0;
    }
};

// 具体访问者:文档渲染访问者
class DocumentRenderVisitor : public DocumentVisitor {
private:
    std::vector<std::string> renderLog_;
    int renderTimeMs_;
    
public:
    DocumentRenderVisitor() : renderTimeMs_(0) {
        std::cout << "🎨 创建文档渲染访问者" << std::endl;
    }
    
    void visit(TextElement* element) override {
        auto startTime = std::chrono::high_resolution_clock::now();
        
        std::string renderInfo = "渲染文本: " + element->getId() + 
                                " [字体:" + element->getFontFamily() + 
                                " 大小:" + std::to_string(element->getFontSize()) + 
                                " 样式:" + element->getStyle() + "]";
        renderLog_.push_back(renderInfo);
        
        // 模拟渲染过程
        std::this_thread::sleep_for(std::chrono::milliseconds(50));
        
        auto endTime = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime);
        renderTimeMs_ += duration.count();
        
        std::cout << "   📝 " << renderInfo << " (耗时:" << duration.count() << "ms)" << std::endl;
    }
    
    void visit(ImageElement* element) override {
        auto startTime = std::chrono::high_resolution_clock::now();
        
        std::string renderInfo = "渲染图片: " + element->getId() + 
                                " [尺寸:" + std::to_string(element->getWidth()) + 
                                "x" + std::to_string(element->getHeight()) + 
                                " 格式:" + element->getFormat() + "]";
        renderLog_.push_back(renderInfo);
        
        // 模拟渲染过程(图片渲染通常更耗时)
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        
        auto endTime = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime);
        renderTimeMs_ += duration.count();
        
        std::cout << "   🖼️  " << renderInfo << " (耗时:" << duration.count() << "ms)" << std::endl;
    }
    
    void visit(TableElement* element) override {
        auto startTime = std::chrono::high_resolution_clock::now();
        
        std::string renderInfo = "渲染表格: " + element->getId() + 
                                " [" + std::to_string(element->getRowCount()) + 
                                "x" + std::to_string(element->getColumnCount()) + "]";
        renderLog_.push_back(renderInfo);
        
        // 模拟渲染过程
        std::this_thread::sleep_for(std::chrono::milliseconds(80));
        
        auto endTime = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime);
        renderTimeMs_ += duration.count();
        
        std::cout << "   📊 " << renderInfo << " (耗时:" << duration.count() << "ms)" << std::endl;
    }
    
    void visit(ParagraphElement* element) override {
        auto startTime = std::chrono::high_resolution_clock::now();
        
        std::string renderInfo = "渲染段落: " + element->getId() + 
                                " [对齐:" + element->getAlignment() + 
                                " 行距:" + std::to_string(element->getLineSpacing()) + "]";
        renderLog_.push_back(renderInfo);
        
        // 模拟渲染过程
        std::this_thread::sleep_for(std::chrono::milliseconds(30));
        
        auto endTime = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime);
        renderTimeMs_ += duration.count();
        
        std::cout << "   📄 " << renderInfo << " (耗时:" << duration.count() << "ms)" << std::endl;
    }
    
    std::string getVisitorName() const override {
        return "文档渲染访问者";
    }
    
    std::string getDescription() const override {
        return "渲染文档中的各种元素";
    }
    
    void reset() override {
        renderLog_.clear();
        renderTimeMs_ = 0;
        std::cout << "🔄 重置渲染状态" << std::endl;
    }
    
    std::string getResults() const override {
        std::stringstream ss;
        ss << "🎨 文档渲染结果:" << std::endl;
        ss << "   渲染元素总数: " << renderLog_.size() << " 个" << std::endl;
        ss << "   总渲染时间: " << renderTimeMs_ << "ms" << std::endl;
        ss << "   平均渲染时间: " << (renderLog_.empty() ? 0 : renderTimeMs_ / renderLog_.size()) << "ms/元素" << std::endl;
        
        return ss.str();
    }
    
    // 渲染访问者特有方法
    void showRenderLog() const {
        std::cout << "\n📋 渲染日志 (" << renderLog_.size() << " 条记录):" << std::endl;
        for (size_t i = 0; i < renderLog_.size(); ++i) {
            std::cout << "   " << (i + 1) << ". " << renderLog_[i] << std::endl;
        }
    }
    
    int getTotalRenderTime() const {
        return renderTimeMs_;
    }
};

UML 武功秘籍图

accepts visits <<interface>> DocumentVisitor +visit(TextElement*) : void +visit(ImageElement*) : void +visit(TableElement*) : void +visit(ParagraphElement*) : void +getVisitorName() : string +getDescription() : string +reset() : void +getResults() : string <<interface>> DocumentElement +accept(DocumentVisitor*) : void +getElementType() : string +getId() : string +getSize() : int +getContentPreview() : string +setPosition(int, int) : void +getPosition() +setStyle(string) : void +getStyle() : string TextElement -string id_ -string content_ -pair<int,int> position_ -string style_ -int fontSize_ -string fontFamily_ +accept(DocumentVisitor*) : void +getElementType() : string +getId() : string +getSize() : int +getContentPreview() : string +getWordCount() : int +getDetailedInfo() : string DocumentStatsVisitor -int textCount_ -int imageCount_ -int tableCount_ -int paragraphCount_ -int totalSize_ -int totalWords_ -vector<string> visitedElements_ +visit(TextElement*) : void +visit(ImageElement*) : void +visit(TableElement*) : void +visit(ParagraphElement*) : void +getVisitorName() : string +getDescription() : string +reset() : void +getResults() : string +showDetailedStats() : void DocumentRenderVisitor -vector<string> renderLog_ -int renderTimeMs_ +visit(TextElement*) : void +visit(ImageElement*) : void +visit(TableElement*) : void +visit(ParagraphElement*) : void +getVisitorName() : string +getDescription() : string +reset() : void +getResults() : string +showRenderLog() : void ImageElement TableElement ParagraphElement

实战演练:高级访问系统

Visitor继续展示更复杂的访问者模式应用:

cpp 复制代码
// 具体访问者:文档导出访问者
class DocumentExportVisitor : public DocumentVisitor {
private:
    std::string exportFormat_;
    std::vector<std::string> exportLog_;
    int exportedElements_;
    std::string outputPath_;
    
public:
    DocumentExportVisitor(const std::string& format = "PDF", const std::string& output = "./export")
        : exportFormat_(format), exportedElements_(0), outputPath_(output) {
        std::cout << "💾 创建文档导出访问者,格式: " << exportFormat_ << std::endl;
    }
    
    void visit(TextElement* element) override {
        std::string exportInfo = "导出文本: " + element->getId() + 
                                " 到 " + outputPath_ + "/" + element->getId() + ".txt";
        exportLog_.push_back(exportInfo);
        exportedElements_++;
        
        // 模拟导出过程
        std::this_thread::sleep_for(std::chrono::milliseconds(40));
        
        std::cout << "   📝 " << exportInfo << std::endl;
    }
    
    void visit(ImageElement* element) override {
        std::string exportInfo = "导出图片: " + element->getId() + 
                                " 到 " + outputPath_ + "/" + element->getId() + "." + 
                                element->getFormat().substr(0, 3);
        exportLog_.push_back(exportInfo);
        exportedElements_++;
        
        // 模拟导出过程
        std::this_thread::sleep_for(std::chrono::milliseconds(120));
        
        std::cout << "   🖼️  " << exportInfo << std::endl;
    }
    
    void visit(TableElement* element) override {
        std::string exportInfo = "导出表格: " + element->getId() + 
                                " 到 " + outputPath_ + "/" + element->getId() + ".csv";
        exportLog_.push_back(exportInfo);
        exportedElements_++;
        
        // 模拟导出过程
        std::this_thread::sleep_for(std::chrono::milliseconds(90));
        
        std::cout << "   📊 " << exportInfo << std::endl;
    }
    
    void visit(ParagraphElement* element) override {
        std::string exportInfo = "导出段落: " + element->getId() + 
                                " 到 " + outputPath_ + "/" + element->getId() + ".html";
        exportLog_.push_back(exportInfo);
        exportedElements_++;
        
        // 模拟导出过程
        std::this_thread::sleep_for(std::chrono::milliseconds(60));
        
        std::cout << "   📄 " << exportInfo << std::endl;
    }
    
    std::string getVisitorName() const override {
        return "文档导出访问者";
    }
    
    std::string getDescription() const override {
        return "将文档元素导出为" + exportFormat_ + "格式";
    }
    
    void reset() override {
        exportLog_.clear();
        exportedElements_ = 0;
        std::cout << "🔄 重置导出状态" << std::endl;
    }
    
    std::string getResults() const override {
        std::stringstream ss;
        ss << "💾 文档导出结果:" << std::endl;
        ss << "   导出格式: " << exportFormat_ << std::endl;
        ss << "   输出路径: " << outputPath_ << std::endl;
        ss << "   导出元素总数: " << exportedElements_ << " 个" << std::endl;
        
        return ss.str();
    }
    
    // 导出访问者特有方法
    void setExportFormat(const std::string& format) {
        exportFormat_ = format;
        std::cout << "🔄 设置导出格式: " << exportFormat_ << std::endl;
    }
    
    void setOutputPath(const std::string& path) {
        outputPath_ = path;
        std::cout << "🔄 设置输出路径: " << outputPath_ << std::endl;
    }
    
    void showExportSummary() const {
        std::cout << "\n📤 导出摘要:" << std::endl;
        std::cout << getResults();
        
        std::cout << "\n📋 导出文件列表:" << std::endl;
        for (size_t i = 0; i < exportLog_.size(); ++i) {
            std::cout << "   " << (i + 1) << ". " << exportLog_[i] << std::endl;
        }
    }
};

// 具体访问者:拼写检查访问者
class SpellCheckVisitor : public DocumentVisitor {
private:
    std::vector<std::string> spellingErrors_;
    std::vector<std::string> checkedElements_;
    int totalWordsChecked_;
    
public:
    SpellCheckVisitor() : totalWordsChecked_(0) {
        std::cout << "🔍 创建拼写检查访问者" << std::endl;
    }
    
    void visit(TextElement* element) override {
        std::string text = element->getContent();
        int wordCount = element->getWordCount();
        totalWordsChecked_ += wordCount;
        checkedElements_.push_back("检查文本: " + element->getId() + " (字数:" + std::to_string(wordCount) + ")");
        
        // 模拟拼写检查(简化实现)
        std::vector<std::string> errors = simulateSpellCheck(text);
        for (const auto& error : errors) {
            spellingErrors_.push_back("文本[" + element->getId() + "]: " + error);
        }
        
        std::cout << "   📝 检查文本: " << element->getId() 
                  << " (字数:" << wordCount << ", 错误:" << errors.size() << ")" << std::endl;
    }
    
    void visit(ImageElement* element) override {
        checkedElements_.push_back("跳过图片: " + element->getId());
        std::cout << "   🖼️  跳过图片: " << element->getId() << " (不支持图片拼写检查)" << std::endl;
    }
    
    void visit(TableElement* element) override {
        int tableWords = 0;
        int tableErrors = 0;
        
        // 检查表格中的每个单元格
        for (int i = 0; i < element->getRowCount(); ++i) {
            for (int j = 0; j < element->getColumnCount(); ++j) {
                std::string cellContent = element->getCell(i, j);
                std::vector<std::string> errors = simulateSpellCheck(cellContent);
                tableErrors += errors.size();
                
                // 估算单词数
                std::istringstream iss(cellContent);
                tableWords += std::distance(std::istream_iterator<std::string>(iss), 
                                           std::istream_iterator<std::string>());
            }
        }
        
        totalWordsChecked_ += tableWords;
        checkedElements_.push_back("检查表格: " + element->getId() + " (单元格:" + std::to_string(element->getTotalCells()) + ")");
        
        if (tableErrors > 0) {
            spellingErrors_.push_back("表格[" + element->getId() + "]: " + std::to_string(tableErrors) + " 个拼写错误");
        }
        
        std::cout << "   📊 检查表格: " << element->getId() 
                  << " (单元格:" << element->getTotalCells() << ", 错误:" << tableErrors << ")" << std::endl;
    }
    
    void visit(ParagraphElement* element) override {
        checkedElements_.push_back("检查段落: " + element->getId() + " (子元素:" + std::to_string(element->getChildCount()) + ")");
        std::cout << "   📄 检查段落: " << element->getId() 
                  << " (将递归检查所有子元素)" << std::endl;
        // 注意:ParagraphElement的accept方法会递归调用子元素的accept
    }
    
    std::string getVisitorName() const override {
        return "拼写检查访问者";
    }
    
    std::string getDescription() const override {
        return "检查文档中的拼写错误";
    }
    
    void reset() override {
        spellingErrors_.clear();
        checkedElements_.clear();
        totalWordsChecked_ = 0;
        std::cout << "🔄 重置拼写检查状态" << std::endl;
    }
    
    std::string getResults() const override {
        std::stringstream ss;
        ss << "🔍 拼写检查结果:" << std::endl;
        ss << "   检查元素总数: " << checkedElements_.size() << " 个" << std::endl;
        ss << "   检查单词总数: " << totalWordsChecked_ << " 个" << std::endl;
        ss << "   发现拼写错误: " << spellingErrors_.size() << " 个" << std::endl;
        ss << "   错误率: " << std::fixed << std::setprecision(2) 
           << (totalWordsChecked_ > 0 ? (spellingErrors_.size() * 100.0 / totalWordsChecked_) : 0) << "%" << std::endl;
        
        return ss.str();
    }
    
    // 拼写检查访问者特有方法
    void showSpellingErrors() const {
        if (spellingErrors_.empty()) {
            std::cout << "✅ 未发现拼写错误" << std::endl;
            return;
        }
        
        std::cout << "\n❌ 拼写错误列表 (" << spellingErrors_.size() << " 个):" << std::endl;
        for (size_t i = 0; i < spellingErrors_.size(); ++i) {
            std::cout << "   " << (i + 1) << ". " << spellingErrors_[i] << std::endl;
        }
    }
    
    double getErrorRate() const {
        return totalWordsChecked_ > 0 ? (spellingErrors_.size() * 100.0 / totalWordsChecked_) : 0.0;
    }
    
private:
    std::vector<std::string> simulateSpellCheck(const std::string& text) {
        std::vector<std::string> errors;
        
        // 简化的拼写检查逻辑
        std::istringstream iss(text);
        std::string word;
        while (iss >> word) {
            // 模拟检查:假设包含数字或大写的单词可能有错误
            if (std::any_of(word.begin(), word.end(), ::isdigit) ||
                std::any_of(word.begin(), word.end(), ::isupper)) {
                errors.push_back("可疑单词: \"" + word + "\"");
            }
        }
        
        return errors;
    }
};

// 文档结构类
class Document {
private:
    std::string title_;
    std::vector<std::shared_ptr<DocumentElement>> elements_;
    std::vector<std::shared_ptr<DocumentVisitor>> visitorHistory_;
    
public:
    Document(const std::string& title) : title_(title) {
        std::cout << "📚 创建文档: " << title_ << std::endl;
    }
    
    void addElement(std::shared_ptr<DocumentElement> element) {
        elements_.push_back(element);
        std::cout << "➕ 添加元素: " << element->getId() << " 到文档" << std::endl;
    }
    
    void removeElement(const std::string& elementId) {
        elements_.erase(
            std::remove_if(elements_.begin(), elements_.end(),
                [&elementId](const std::shared_ptr<DocumentElement>& element) {
                    return element->getId() == elementId;
                }),
            elements_.end()
        );
        std::cout << "🗑️  从文档中移除元素: " << elementId << std::endl;
    }
    
    void accept(DocumentVisitor* visitor) {
        std::cout << "\n🎯 文档接受访问者: " << visitor->getVisitorName() << std::endl;
        std::cout << "   描述: " << visitor->getDescription() << std::endl;
        
        auto startTime = std::chrono::high_resolution_clock::now();
        
        // 重置访问者状态
        visitor->reset();
        
        // 让访问者访问所有元素
        for (auto& element : elements_) {
            element->accept(visitor);
        }
        
        auto endTime = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime);
        
        std::cout << "✅ 访问完成,总耗时: " << duration.count() << "ms" << std::endl;
        std::cout << visitor->getResults() << std::endl;
        
        // 记录访问历史
        // visitorHistory_.push_back(std::shared_ptr<DocumentVisitor>(visitor)); // 注意:这里需要适当的内存管理
    }
    
    void showDocumentInfo() const {
        std::cout << "\n📄 文档信息: " << title_ << std::endl;
        std::cout << "   元素总数: " << elements_.size() << " 个" << std::endl;
        
        int totalSize = 0;
        std::map<std::string, int> typeCounts;
        
        for (const auto& element : elements_) {
            totalSize += element->getSize();
            typeCounts[element->getElementType()]++;
        }
        
        std::cout << "   总大小: " << totalSize << " 单位" << std::endl;
        std::cout << "   元素类型分布:" << std::endl;
        for (const auto& pair : typeCounts) {
            std::cout << "     • " << pair.first << ": " << pair.second << " 个" << std::endl;
        }
    }
    
    void listAllElements() const {
        std::cout << "\n📋 文档元素列表 (" << elements_.size() << " 个):" << std::endl;
        for (size_t i = 0; i < elements_.size(); ++i) {
            std::cout << "   " << (i + 1) << ". " << elements_[i]->getContentPreview() << std::endl;
        }
    }
    
    std::string getTitle() const { return title_; }
    int getElementCount() const { return elements_.size(); }
    
    // 批量操作
    void applyToAllElements(std::function<void(DocumentElement*)> operation) {
        for (auto& element : elements_) {
            operation(element.get());
        }
    }
};

完整测试代码

cpp 复制代码
// 测试访问者模式
void testVisitorPattern() {
    std::cout << "=== 访问者模式测试开始 ===" << std::endl;
    
    // 创建文档和元素
    std::cout << "\n--- 创建测试文档 ---" << std::endl;
    Document document("测试文档");
    
    // 创建各种元素
    auto text1 = std::make_shared<TextElement>("text1", "这是一个测试文本内容,用于演示访问者模式。");
    auto text2 = std::make_shared<TextElement>("text2", "另一个文本元素,包含更多的文字内容。");
    
    auto image1 = std::make_shared<ImageElement>("image1", "photo.jpg", 800, 600, 2.5);
    auto image2 = std::make_shared<ImageElement>("image2", "diagram.png", 1200, 800, 1.8);
    
    auto table1 = std::make_shared<TableElement>("table1", 4, 3, "数据表格");
    table1->setCell(0, 0, "姓名");
    table1->setCell(0, 1, "年龄");
    table1->setCell(0, 2, "职业");
    
    auto paragraph1 = std::make_shared<ParagraphElement>("paragraph1", "justified");
    paragraph1->addChild(std::make_shared<TextElement>("child_text1", "段落中的第一个文本。"));
    paragraph1->addChild(std::make_shared<TextElement>("child_text2", "段落中的第二个文本。"));
    
    // 添加元素到文档
    document.addElement(text1);
    document.addElement(image1);
    document.addElement(table1);
    document.addElement(paragraph1);
    document.addElement(text2);
    document.addElement(image2);
    
    // 显示文档信息
    document.showDocumentInfo();
    document.listAllElements();
    
    // 测试各种访问者
    std::cout << "\n--- 测试统计访问者 ---" << std::endl;
    DocumentStatsVisitor statsVisitor;
    document.accept(&statsVisitor);
    statsVisitor.showDetailedStats();
    
    std::cout << "\n--- 测试渲染访问者 ---" << std::endl;
    DocumentRenderVisitor renderVisitor;
    document.accept(&renderVisitor);
    renderVisitor.showRenderLog();
    
    std::cout << "\n--- 测试导出访问者 ---" << std::endl;
    DocumentExportVisitor exportVisitor("PDF", "./exports");
    document.accept(&exportVisitor);
    exportVisitor.showExportSummary();
    
    std::cout << "\n--- 测试拼写检查访问者 ---" << std::endl;
    SpellCheckVisitor spellCheckVisitor;
    document.accept(&spellCheckVisitor);
    spellCheckVisitor.showSpellingErrors();
    
    std::cout << "\n=== 基础访问者模式测试结束 ===" << std::endl;
}

// 测试复合元素结构
void testCompositeStructure() {
    std::cout << "\n=== 复合结构测试开始 ===" << std::endl;
    
    // 创建复杂的文档结构
    Document complexDocument("复杂文档结构");
    
    // 创建嵌套的段落结构
    auto mainParagraph = std::make_shared<ParagraphElement>("main_para", "left");
    
    auto subParagraph1 = std::make_shared<ParagraphElement>("sub_para1", "left");
    subParagraph1->addChild(std::make_shared<TextElement>("sub_text1", "子段落一的文本内容。"));
    subParagraph1->addChild(std::make_shared<ImageElement>("sub_image1", "icon.png", 32, 32, 0.1));
    
    auto subParagraph2 = std::make_shared<ParagraphElement>("sub_para2", "right");
    subParagraph2->addChild(std::make_shared<TextElement>("sub_text2", "子段落二的文本内容。"));
    subParagraph2->addChild(std::make_shared<TableElement>("sub_table1", 2, 2));
    
    mainParagraph->addChild(subParagraph1);
    mainParagraph->addChild(subParagraph2);
    
    complexDocument.addElement(mainParagraph);
    complexDocument.addElement(std::make_shared<TextElement>("standalone_text", "独立的文本元素。"));
    
    // 显示文档结构
    complexDocument.showDocumentInfo();
    
    // 测试访问者在复合结构上的行为
    std::cout << "\n--- 在复合结构上测试统计访问者 ---" << std::endl;
    DocumentStatsVisitor statsVisitor;
    complexDocument.accept(&statsVisitor);
    statsVisitor.showDetailedStats();
    
    std::cout << "\n--- 在复合结构上测试拼写检查访问者 ---" << std::endl;
    SpellCheckVisitor spellVisitor;
    complexDocument.accept(&spellVisitor);
    spellVisitor.showSpellingErrors();
    
    std::cout << "\n=== 复合结构测试结束 ===" << std::endl;
}

// 测试访问者组合
void testVisitorCombination() {
    std::cout << "\n=== 访问者组合测试开始 ===" << std::endl;
    
    Document document("访问者组合测试");
    
    // 添加测试元素
    document.addElement(std::make_shared<TextElement>("text1", "第一个测试文本。"));
    document.addElement(std::make_shared<ImageElement>("img1", "test.jpg", 400, 300, 1.2));
    document.addElement(std::make_shared<TableElement>("table1", 3, 2, "测试表格"));
    
    // 创建访问者组合
    std::cout << "\n--- 顺序执行多个访问者 ---" << std::endl;
    
    DocumentStatsVisitor statsVisitor;
    DocumentRenderVisitor renderVisitor;
    SpellCheckVisitor spellVisitor;
    
    std::vector<DocumentVisitor*> visitors = {&statsVisitor, &renderVisitor, &spellVisitor};
    
    for (auto visitor : visitors) {
        document.accept(visitor);
        std::cout << std::string(50, '-') << std::endl;
    }
    
    std::cout << "\n=== 访问者组合测试结束 ===" << std::endl;
}

// 实战应用:文档处理系统
class DocumentProcessingSystem {
private:
    std::vector<Document> documents_;
    std::map<std::string, std::unique_ptr<DocumentVisitor>> visitorRegistry_;
    
public:
    DocumentProcessingSystem() {
        std::cout << "🏢 创建文档处理系统" << std::endl;
        initializeVisitorRegistry();
    }
    
    void initializeVisitorRegistry() {
        // 注册各种访问者
        visitorRegistry_["stats"] = std::make_unique<DocumentStatsVisitor>();
        visitorRegistry_["render"] = std::make_unique<DocumentRenderVisitor>();
        visitorRegistry_["export"] = std::make_unique<DocumentExportVisitor>();
        visitorRegistry_["spellcheck"] = std::make_unique<SpellCheckVisitor>();
        
        std::cout << "✅ 初始化 " << visitorRegistry_.size() << " 个访问者" << std::endl;
    }
    
    void createDocument(const std::string& title) {
        documents_.emplace_back(title);
        std::cout << "📄 创建文档: " << title << std::endl;
    }
    
    Document& getDocument(int index) {
        if (index >= 0 && index < documents_.size()) {
            return documents_[index];
        }
        throw std::out_of_range("文档索引越界");
    }
    
    void processDocument(int docIndex, const std::string& visitorType) {
        if (docIndex < 0 || docIndex >= documents_.size()) {
            std::cout << "❌ 无效的文档索引: " << docIndex << std::endl;
            return;
        }
        
        auto it = visitorRegistry_.find(visitorType);
        if (it == visitorRegistry_.end()) {
            std::cout << "❌ 未知的访问者类型: " << visitorType << std::endl;
            return;
        }
        
        std::cout << "\n🔧 处理文档 #" << docIndex << " 使用访问者: " << visitorType << std::endl;
        documents_[docIndex].accept(it->second.get());
    }
    
    void batchProcess(const std::string& visitorType) {
        auto it = visitorRegistry_.find(visitorType);
        if (it == visitorRegistry_.end()) {
            std::cout << "❌ 未知的访问者类型: " << visitorType << std::endl;
            return;
        }
        
        std::cout << "\n🔧 批量处理所有文档使用访问者: " << visitorType << std::endl;
        for (size_t i = 0; i < documents_.size(); ++i) {
            std::cout << "\n--- 处理文档 #" << i << " ---" << std::endl;
            documents_[i].accept(it->second.get());
        }
    }
    
    void showSystemStatus() const {
        std::cout << "\n📊 系统状态" << std::endl;
        std::cout << "==========" << std::endl;
        std::cout << "文档数量: " << documents_.size() << std::endl;
        std::cout << "可用访问者: " << visitorRegistry_.size() << " 个" << std::endl;
        
        for (const auto& pair : visitorRegistry_) {
            std::cout << "  • " << pair.first << ": " << pair.second->getDescription() << std::endl;
        }
    }
    
    void registerCustomVisitor(const std::string& name, std::unique_ptr<DocumentVisitor> visitor) {
        visitorRegistry_[name] = std::move(visitor);
        std::cout << "🆕 注册自定义访问者: " << name << std::endl;
    }
    
    void runDemo() {
        std::cout << "\n🎮 运行文档处理系统演示..." << std::endl;
        std::cout << "========================" << std::endl;
        
        // 创建示例文档
        createDocument("技术报告");
        createDocument("用户手册");
        createDocument("项目提案");
        
        // 为文档添加内容
        setupDemoDocuments();
        
        // 显示系统状态
        showSystemStatus();
        
        // 执行各种处理
        processDocument(0, "stats");
        processDocument(1, "spellcheck");
        batchProcess("render");
        
        std::cout << "\n✅ 文档处理系统演示完成" << std::endl;
    }
    
private:
    void setupDemoDocuments() {
        // 设置第一个文档(技术报告)
        Document& techReport = getDocument(0);
        techReport.addElement(std::make_shared<TextElement>("intro", "本技术报告介绍了系统的设计和实现。"));
        techReport.addElement(std::make_shared<TableElement>("data_table", 5, 4, "性能数据"));
        techReport.addElement(std::make_shared<ImageElement>("arch_diagram", "architecture.png", 800, 600, 2.1));
        
        // 设置第二个文档(用户手册)
        Document& userManual = getDocument(1);
        userManual.addElement(std::make_shared<TextElement>("welcome", "欢迎使用本系统用户手册。"));
        
        auto usageSection = std::make_shared<ParagraphElement>("usage_section", "left");
        usageSection->addChild(std::make_shared<TextElement>("step1", "第一步:启动应用程序。"));
        usageSection->addChild(std::make_shared<TextElement>("step2", "第二步:配置系统参数。"));
        usageSection->addChild(std::make_shared<ImageElement>("config_screen", "config.png", 600, 400, 1.5));
        
        userManual.addElement(usageSection);
        
        // 设置第三个文档(项目提案)
        Document& proposal = getDocument(2);
        proposal.addElement(std::make_shared<TextElement>("exec_summary", "本项目提案旨在开发新一代文档处理系统。"));
        proposal.addElement(std::make_shared<TableElement>("budget", 4, 3, "项目预算"));
        proposal.addElement(std::make_shared<TextElement>("timeline", "项目计划在六个月内完成。"));
        
        std::cout << "✅ 设置演示文档内容完成" << std::endl;
    }
};

// 高级应用:条件访问者
class ConditionalVisitor : public DocumentVisitor {
private:
    std::function<bool(DocumentElement*)> condition_;
    std::unique_ptr<DocumentVisitor> trueVisitor_;
    std::unique_ptr<DocumentVisitor> falseVisitor_;
    int trueCount_;
    int falseCount_;
    
public:
    ConditionalVisitor(std::function<bool(DocumentElement*)> condition,
                      std::unique_ptr<DocumentVisitor> trueVisitor,
                      std::unique_ptr<DocumentVisitor> falseVisitor)
        : condition_(condition), trueVisitor_(std::move(trueVisitor)),
          falseVisitor_(std::move(falseVisitor)), trueCount_(0), falseCount_(0) {
        std::cout << "🎭 创建条件访问者" << std::endl;
    }
    
    void visit(TextElement* element) override {
        processElement(element);
    }
    
    void visit(ImageElement* element) override {
        processElement(element);
    }
    
    void visit(TableElement* element) override {
        processElement(element);
    }
    
    void visit(ParagraphElement* element) override {
        processElement(element);
    }
    
    std::string getVisitorName() const override {
        return "条件访问者[" + trueVisitor_->getVisitorName() + "|" + falseVisitor_->getVisitorName() + "]";
    }
    
    std::string getDescription() const override {
        return "基于条件选择访问者的条件访问者";
    }
    
    void reset() override {
        trueCount_ = falseCount_ = 0;
        trueVisitor_->reset();
        falseVisitor_->reset();
    }
    
    std::string getResults() const override {
        std::stringstream ss;
        ss << "🎭 条件访问者结果:" << std::endl;
        ss << "   满足条件的元素: " << trueCount_ << " 个" << std::endl;
        ss << "   不满足条件的元素: " << falseCount_ << " 个" << std::endl;
        ss << "\n真分支结果:" << std::endl;
        ss << trueVisitor_->getResults() << std::endl;
        ss << "\n假分支结果:" << std::endl;
        ss << falseVisitor_->getResults();
        
        return ss.str();
    }
    
private:
    void processElement(DocumentElement* element) {
        if (condition_(element)) {
            trueCount_++;
            // 动态分派到正确的visit方法
            element->accept(trueVisitor_.get());
        } else {
            falseCount_++;
            element->accept(falseVisitor_.get());
        }
    }
};

int main() {
    std::cout << "🌈 设计模式武林大会 - 访问者模式演示 🌈" << std::endl;
    std::cout << "=====================================" << std::endl;
    
    // 测试基础访问者模式
    testVisitorPattern();
    
    // 测试复合结构
    testCompositeStructure();
    
    // 测试访问者组合
    testVisitorCombination();
    
    // 运行文档处理系统演示
    std::cout << "\n=== 文档处理系统演示 ===" << std::endl;
    DocumentProcessingSystem processingSystem;
    processingSystem.runDemo();
    
    // 测试条件访问者
    std::cout << "\n=== 条件访问者测试 ===" << std::endl;
    Document testDoc("条件访问者测试");
    testDoc.addElement(std::make_shared<TextElement>("text1", "重要文本内容"));
    testDoc.addElement(std::make_shared<ImageElement>("img1", "photo.jpg", 100, 100, 0.5));
    testDoc.addElement(std::make_shared<TextElement>("text2", "普通文本"));
    
    auto conditionalVisitor = std::make_unique<ConditionalVisitor>(
        [](DocumentElement* elem) { return elem->getElementType() == "Text"; },
        std::make_unique<DocumentStatsVisitor>(),
        std::make_unique<DocumentRenderVisitor>()
    );
    
    testDoc.accept(conditionalVisitor.get());
    
    std::cout << "\n🎉 访问者模式演示全部完成!" << std::endl;
    
    return 0;
}

访问者模式的武学心得

适用场景

  • 复杂的对象结构:当一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作时
  • 需要很多操作:需要对一个对象结构中的对象进行很多不同且不相关的操作,而你想避免让这些操作"污染"这些对象的类时
  • 定义操作接口:定义对象结构的类很少改变,但经常需要在此结构上定义新的操作时
  • 累积状态:需要在遍历对象结构时累积状态时

优点

  • 开闭原则:可以引入新的访问者而不必修改现有元素类
  • 单一职责原则:可将同一行为的不同版本移到同一个类中
  • 累积状态:访问者可以在访问各个元素时累积状态
  • 灵活性:将相关的操作集中在一个访问者对象中

缺点

  • 增加新元素困难:每增加一个新的元素类,都要在每一个访问者类中增加相应的具体操作
  • 破坏封装:访问者模式要求访问者对象访问并调用元素对象的操作,这可能会破坏元素的封装性
  • 依赖具体类:访问者模式依赖具体类,而不是抽象类

武林高手的点评

Iterator 赞叹道:"Visitor 兄的操作分离确实精妙!能够如此优雅地在不修改对象结构的情况下添加新操作,这在需要处理复杂对象结构的系统中确实无人能及。"

Composite 也点头称赞:"Visitor 兄专注于对元素的操作,而我更关注元素的结构组织。我们经常一起合作,处理复杂的层次结构。"

Visitor 谦虚回应:"诸位过奖了。每个模式都有其适用场景。在需要对复杂对象结构执行多种操作时,我的访问者模式确实能发挥重要作用。但在需要统一遍历接口时,Iterator 兄的方法更加合适。"

下章预告

在Visitor展示完他那精妙的访问艺术后,Mediator 在人群中来回穿梭、忙于调停的和事佬走出。

"Visitor 兄的操作分离确实精妙,但在对象间通信复杂、相互依赖时,需要更加中心化的协调方式。" Mediator 忙碌地说道,"下一章,我将展示如何通过中介者模式来封装对象间的交互,使它们不必直接相互引用,从而使其耦合松散!"

架构老人满意地点头:"善!对象间的协调通信确实是构建松耦合系统的关键。下一章,就请 Mediator 展示他的中介艺术!"


欲知 Mediator 如何通过中介者模式实现对象间的松耦合通信,且听下回分解!

相关推荐
大飞pkz4 天前
【设计模式】访问者模式
开发语言·设计模式·c#·访问者模式
charlie1145141914 天前
精读 C++20 设计模式:行为型设计模式 — 访问者模式
c++·学习·设计模式·访问者模式·c++20
new_daimond11 天前
设计模式-访问者模式详解
设计模式·访问者模式
努力也学不会java13 天前
【设计模式】访问者模式
java·设计模式·访问者模式
TechNomad1 个月前
设计模式:访问者模式(Visitor Pattern)
设计模式·访问者模式
牛奶咖啡131 个月前
学习设计模式《二十四》——访问者模式
学习·设计模式·访问者模式·认识访问者模式·访问者模式的优缺点·何时选用访问者模式·访问者模式的使用示例
饕餮争锋2 个月前
设计模式笔记_行为型_访问者模式
笔记·设计模式·访问者模式
蝸牛ちゃん2 个月前
设计模式(二十四)行为型:访问者模式详解
设计模式·系统架构·软考高级·访问者模式