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

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

风云再起,访问学者登场

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

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

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

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

访问者模式的核心要义

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

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

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

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

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

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

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

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

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

基础框架搭建

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

#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展示了各种文档元素的具体实现:

// 具体元素:文本元素
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展示了各种文档处理操作的具体实现:

// 具体访问者:文档统计访问者
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继续展示更复杂的访问者模式应用:

// 具体访问者:文档导出访问者
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());
                                                            }
                                                            }
                                                            };

完整测试代码

// 测试访问者模式
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 如何通过中介者模式实现对象间的松耦合通信,且听下回分解!

posted on 2025-11-06 15:58  slgkaifa  阅读(9)  评论(0)    收藏  举报

导航