访问者模式原始版
#include <iostream>
#include "common/log.h"
#include <limits>
#include <vector>
#include <span>
#include <array>
#include <type_traits>
#include <cmath>
#include <memory>
using namespace AdsonLib;
//访问者模式:Element的种类固定,但是操作Element的方法经常变
//如果在Element中增加操作方法,需要经常修改Element,为此把操作
//方法封装到Visitor中,扩展Visitor方便。
struct Element;
struct ElementA;
struct ElementB;
struct Visitor {
virtual void VisitElementA(ElementA &a) = 0;
virtual void VisitElementB(ElementB &b) = 0;
virtual ~Visitor(){}
};
struct Element {
virtual void accept(Visitor &vis) = 0;
virtual ~Element(){}
int val = 1;
};
struct ElementA : public Element{
virtual void accept(Visitor &vis) override {
vis.VisitElementA(*this);
}
};
struct ElementB : public Element{
virtual void accept(Visitor &vis) override {
vis.VisitElementB(*this);
}
};
struct VisitorA : public Visitor {
int sum = 1;
virtual void VisitElementA(ElementA &a) override {
LOG(INFO) << "VisitorA vis ElementA: " << a.val;
sum += a.val;
}
virtual void VisitElementB(ElementB &b) override {
LOG(INFO) << "VisitorA vis ElementB: " << b.val;
sum *=b.val;
}
int total() {
return sum;
}
};
struct VisitorB : public Visitor {
int mul = 1;
virtual void VisitElementA(ElementA &a) override {
LOG(INFO) << "VisitorA vis ElementA: " << a.val;
mul *= a.val;
}
virtual void VisitElementB(ElementB &b) override {
LOG(INFO) << "VisitorA vis ElementB: " << b.val;
mul += b.val;
}
int multi() {
return mul;
}
};
struct ObjectStructure{
ObjectStructure(){
ElementA a1;
a1.val = 1;
objs.push_back(std::make_shared<ElementA>(a1));
a1.val = 2;
objs.push_back(std::make_shared<ElementA>(a1));
ElementB b1;
b1.val = 3;
objs.push_back(std::make_shared<ElementB>(b1));
b1.val = 4;
objs.push_back(std::make_shared<ElementB>(b1));
}
void calc(Visitor &vis){
for(auto && e : objs) {
e->accept(vis);
}
}
std::vector<std::shared_ptr<Element>> objs;
};
void common_test(){
ObjectStructure os;
VisitorA VA;
VisitorB VB;
os.calc(VA);
LOG(INFO) << "visit by VA: " << VA.total();
os.calc(VB);
LOG(INFO) << "visit by VB: " << VB.multi();
}
int main(int argc, char *argv[]) {
common_test();
}
奇异模板递归,把dispatch放到父类
template<typename T>
struct Base{};
//子类传递到父类中了,父类就能用子类类型了,这就是奇异模板递归
struct Der:public Base<Der>{};
#include <iostream>
#include "common/log.h"
#include <limits>
#include <vector>
#include <span>
#include <array>
#include <type_traits>
#include <cmath>
#include <memory>
using namespace AdsonLib;
//访问者模式:Element的种类固定,但是操作Element的方法经常变
//如果在Element中增加操作方法,需要经常修改Element,为此把操作
//方法封装到Visitor中,扩展Visitor方便。
struct Element;
struct ElementA;
struct ElementB;
struct Visitor {
virtual void Visit(ElementA &a) = 0;
virtual void Visit(ElementB &b) = 0;
virtual ~Visitor(){}
};
struct Element {
virtual void accept(Visitor &vis) = 0;
virtual ~Element(){}
int val = 1;
};
template<typename T>
struct AutoDispatchElement : public Element {
virtual void accept(Visitor &vis) override {
vis.Visit(static_cast<T&>(*this));
}
};
struct ElementA : public AutoDispatchElement<ElementA>{
};
struct ElementB : public AutoDispatchElement<ElementB>{
};
struct VisitorA : public Visitor {
int sum = 1;
virtual void Visit(ElementA &a) override {
LOG(INFO) << "VisitorA vis ElementA: " << a.val;
sum += a.val;
}
virtual void Visit(ElementB &b) override {
LOG(INFO) << "VisitorA vis ElementB: " << b.val;
sum *=b.val;
}
int total() {
return sum;
}
};
struct VisitorB : public Visitor {
int mul = 1;
virtual void Visit(ElementA &a) override {
LOG(INFO) << "VisitorA vis ElementA: " << a.val;
mul *= a.val;
}
virtual void Visit(ElementB &b) override {
LOG(INFO) << "VisitorA vis ElementB: " << b.val;
mul += b.val;
}
int multi() {
return mul;
}
};
struct ObjectStructure{
ObjectStructure(){
ElementA a1;
a1.val = 1;
objs.push_back(std::make_shared<ElementA>(a1));
a1.val = 2;
objs.push_back(std::make_shared<ElementA>(a1));
ElementB b1;
b1.val = 3;
objs.push_back(std::make_shared<ElementB>(b1));
b1.val = 4;
objs.push_back(std::make_shared<ElementB>(b1));
}
void calc(Visitor &vis){
for(auto && e : objs) {
e->accept(vis);
}
}
std::vector<std::shared_ptr<Element>> objs;
};
void common_test(){
ObjectStructure os;
VisitorA VA;
VisitorB VB;
os.calc(VA);
LOG(INFO) << "visit by VA: " << VA.total();
os.calc(VB);
LOG(INFO) << "visit by VB: " << VB.multi();
}
int main(int argc, char *argv[]) {
common_test();
}
std::variant, std::visit, if constexpr版访问者
#include <iostream>
#include "common/log.h"
#include <limits>
#include <vector>
#include <span>
#include <array>
#include <type_traits>
#include <cmath>
#include <memory>
#include <variant>
using namespace AdsonLib;
struct ElementA{
};
struct ElementB{};
using Element = std::variant<ElementA, ElementB>;
struct Visitor{
void operator()(ElementA &e) {
LOG(INFO) << "visit a";
}
void operator()(ElementB &e) {
LOG(INFO) << "visit b";
}
};
void common_test(){
std::vector<Element> vecs;
vecs.push_back(ElementA());
vecs.push_back(ElementB());
vecs.push_back(ElementA());
vecs.push_back(ElementB());
for(auto && e: vecs){
std::visit([](auto &&arg){
LOG(INFO) << "arg";
}, e);
}
LOG(INFO) << "------------";
for(auto && e: vecs){
std::visit([](auto &&arg){
using T = std::decay_t<decltype(arg)>;
if constexpr(std::is_same_v<T, ElementA>){
LOG(INFO) << "ElementA";
} else if constexpr(std::is_same_v<T, ElementB>){
LOG(INFO) << "ElementB";
}
}, e);
}
LOG(INFO) << "------------";
for(auto && e: vecs){
std::visit(Visitor(), e);
}
}
int main(int argc, char *argv[]) {
common_test();
}