访问者模式 (Visitor Pattern)
意图:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
基础组件
- Visitor (访问者):声明访问操作接口
- ConcreteVisitor (具体访问者):实现访问操作
- Element (元素):定义接受访问者的接口
- ConcreteElement (具体元素):实现接受访问者方法
- ObjectStructure (对象结构):包含元素集合,提供遍历接口
继承/实现关系
Visitor <|-- ConcreteVisitor
Element <|-- ConcreteElement
ConcreteElement --> Visitor (接受访问者)
ObjectStructure --> Element (包含元素集合)
应用场景
- 需要对对象结构中的对象进行不同且不相关的操作
- 需要在不改变元素类的前提下增加新操作
- 对象结构稳定,但需要频繁添加新操作
C++ 实现(文档元素导出)
#include <iostream>
#include <string>
#include <vector>
#include <memory>
/*
* 访问者模式
* 意图:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
* 基础组件:
* Visitor (访问者):声明访问操作接口
* ConcreteVisitor (具体访问者):实现访问操作
* Element (元素):定义接受访问者的接口
* ConcreteElement (具体元素):实现接受访问者方法
* ObjectStructure (对象结构):包含元素集合,提供遍历接口
* 继承/实现关系:
* ConcreteVisitor 类实现 Visitor 接口,定义具体的访问操作。
* ConcreteElement 类实现 Element 接口,定义接受访问者的方法。
* ConcreteElement 中接受一个 Visitor 对象,并调用其访问方法。
* ObjectStructure 类维护一个元素集合,并提供遍历方法,允许访问者访问每个元素。
*/
class PdfExporter;
class HtmlExporter;
// 元素接口
class DocumentElement {
public:
virtual ~DocumentElement() = default;
// 这个方法接受一个访问者对象,并且调用访问者的相应方法来访问本对象的数据。
virtual void accept(class ExporterVisitor* visitor) = 0;
};
// 访问者接口
class ExporterVisitor {
public:
virtual ~ExporterVisitor() = default;
virtual void visit(class TextElement* text) = 0;
virtual void visit(class ImageElement* image) = 0;
virtual void visit(class VideoElement* video) = 0;
};
// 具体元素:文本元素
class TextElement : public DocumentElement {
public:
explicit TextElement(const std::string& content) : content_(content) {}
void accept(ExporterVisitor* visitor) override {
visitor->visit(this);
}
const std::string& getContent() const { return content_; }
private:
std::string content_;
};
// 具体元素:图片元素
class ImageElement : public DocumentElement {
public:
explicit ImageElement(const std::string& path) : path_(path) {}
void accept(ExporterVisitor* visitor) override {
visitor->visit(this);
}
const std::string& getPath() const { return path_; }
private:
std::string path_;
};
// 具体元素:视频元素
class VideoElement : public DocumentElement {
public:
explicit VideoElement(const std::string& url) : url_(url) {}
void accept(ExporterVisitor* visitor) override {
visitor->visit(this);
}
const std::string& getUrl() const { return url_; }
private:
std::string url_;
};
// 具体访问者:PDF导出
class PdfExporter : public ExporterVisitor {
public:
void visit(TextElement* text) override {
std::cout << "Exporting text to PDF: " << text->getContent() << "\n";
}
void visit(ImageElement* image) override {
std::cout << "Exporting image to PDF: " << image->getPath() << "\n";
}
void visit(VideoElement* video) override {
std::cout << "Exporting video to PDF is not supported.\n";
}
};
// 具体访问者:HTML导出
class HtmlExporter : public ExporterVisitor {
public:
void visit(TextElement* text) override {
std::cout << "Exporting text to HTML: " << text->getContent() << "\n";
}
void visit(ImageElement* image) override {
std::cout << "Exporting image to HTML: <img src=\""
<< image->getPath() << "\">\n";
}
void visit(VideoElement* video) override {
std::cout << "Exporting video to HTML: <video src=\""
<< video->getUrl() << "\"></video>\n";
}
};
// 对象结构:文档
class Document {
public:
void addElement(std::unique_ptr<DocumentElement> elem) {
elements_.push_back(std::move(elem));
}
void accept(ExporterVisitor* visitor) {
for (const auto& elem : elements_) {
elem->accept(visitor);
}
}
private:
std::vector<std::unique_ptr<DocumentElement>> elements_;
};
void VisitorPattern()
{
std::cout << std::string(13, '-') << " Visitor Pattern " << std::string(13, '-') << "\n";
Document doc;
doc.addElement(std::make_unique<TextElement>("Hello, World!"));
doc.addElement(std::make_unique<ImageElement>("photo.jpg"));
doc.addElement(std::make_unique<VideoElement>("movie.mp4"));
PdfExporter pdfExporter;
HtmlExporter htmlExporter;
std::cout << "Exporting to PDF:\n";
doc.accept(&pdfExporter);
std::cout << "\nExporting to HTML:\n";
doc.accept(&htmlExporter);
}
组件对应关系
ExporterVisitor→ 访问者接口PdfExporter/HtmlExporter→ 具体访问者DocumentElement→ 元素接口TextElement/ImageElement/VideoElement→ 具体元素Document→ 对象结构
1006

被折叠的 条评论
为什么被折叠?



