C++ 設計模式之訪問者模式
簡介
1、訪問者模式 (Visitor)是一種行為型設計模式,它表示一個作用于某對象結構中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作。 使用該模式可以在不修改已有程序結構的前提下,通過添加額外的訪問者類實現新的操作。
2、訪問者模式 (Visitor)應用場景包括但不限于:
2.1、對象結構比較穩定,但操作經常變化的程序。
2.2、需要對一個對象結構中的對象進行很多不同而且不相關的操作,而你想避免讓這些操作“污染”這些對象的類。
3、訪問者模式 (Visitor)的構成
3.1、訪問者(Visitor):定義了一個訪問操作中的元素的接口。這個接口使得訪問者可以不修改類的結構就可以增加新的操作。
class DocumentVisitor
{
public:virtual ~DocumentVisitor() {}virtual void visitParagraph(class ParagraphElement* element) = 0;virtual void visitImage(class ImageElement* element) = 0;virtual void visitTable(class TableElement* element) = 0;
};
3.2、元素(Element):聲明一個接受訪問者對象的接口。這個接口通常包含一個或多個由訪問者接口定義的方法。
class DocumentElement
{
public:virtual ~DocumentElement() {}virtual void accept(DocumentVisitor* visitor) = 0;
};
4、訪問者模式 (Visitor)的優點
4.1、封裝性: 可以在不改變元素類的情況下定義新的操作。
4.2、擴展性: 新的訪問者可以很容易地添加新的操作。
4.3、分離關注點: 移動相關的操作集中到訪問者中,而不是分散在元素類中。
5、訪問者模式 (Visitor)的缺點
5.1、違反封裝: 訪問者可能需要訪問元素的內部細節,這通常意味著元素必須暴露一些原本應該是私有的數據。
5.2、復雜度: 可以使系統變得更加復雜,特別是當系統有大量元素時。
5.3、對象結構變化困難: 如果經常改變對象結構的元素類,那么維護訪問者模式將會非常麻煩。
簡單示例
1、定義
// 抽象訪問者
class DocumentVisitor
{
public:virtual ~DocumentVisitor() {}virtual void visitParagraph(class ParagraphElement* element) = 0;virtual void visitImage(class ImageElement* element) = 0;virtual void visitTable(class TableElement* element) = 0;
};// 元素基類
class DocumentElement
{
public:virtual ~DocumentElement() {}virtual void accept(DocumentVisitor* visitor) = 0;
};class ParagraphElement : public DocumentElement
{
public:void accept(DocumentVisitor* visitor);
};class ImageElement : public DocumentElement
{
public:void accept(DocumentVisitor* visitor);
};class TableElement : public DocumentElement
{
public:void accept(DocumentVisitor* visitor);
};// 渲染訪問者
class RenderVisitor : public DocumentVisitor
{
public:void visitParagraph(class ParagraphElement* element);void visitImage(class ImageElement* element);void visitTable(class TableElement* element);
};// 檢查訪問者
class CheckVisitor : public DocumentVisitor
{
public:void visitParagraph(class ParagraphElement* element);void visitImage(class ImageElement* element);void visitTable(class TableElement* element);
};
2、實現
void ParagraphElement::accept(DocumentVisitor* visitor)
{visitor->visitParagraph(this);
}void ImageElement::accept(DocumentVisitor* visitor)
{visitor->visitImage(this);
}void TableElement::accept(DocumentVisitor* visitor)
{visitor->visitTable(this);
}void RenderVisitor::visitParagraph(class ParagraphElement* element)
{std::cout << "Render Paragraph" << std::endl;
}void RenderVisitor::visitImage(class ImageElement* element)
{std::cout << "Render Image" << std::endl;
}void RenderVisitor::visitTable(class TableElement* element)
{std::cout << "Render Table" << std::endl;
}void CheckVisitor::visitParagraph(class ParagraphElement* element)
{std::cout << "Check Paragraph" << std::endl;
}void CheckVisitor::visitImage(class ImageElement* element)
{std::cout << "Check Image" << std::endl;
}void CheckVisitor::visitTable(class TableElement* element)
{std::cout << "Check Table" << std::endl;
}
3、調用
std::vector<DocumentElement*> vecDoc = {new ParagraphElement(),new ImageElement(),new TableElement()
};
RenderVisitor renderVisitor;
CheckVisitor checkVisitor;for (auto elem : vecDoc)
{elem->accept(&renderVisitor);elem->accept(&checkVisitor);
}for (auto el : vecDoc)
{delete el;
}