为什么'visitor pattern'要求每个类继承具有accept()函数的VisitorHost接口类?

Why does 'visitor pattern' asks each class to inherit VisitorHost interface class which has accept() function?

本文关键字:accept 函数 接口 VisitorHost pattern visitor 为什么 继承      更新时间:2023-10-16

我正在学习一个设计模式,访问者模式,在c++中。

首先,我复制下面的两个实践代码。第一个是"我的测试代码",第二个是我课本中"正常访客模式"的简化代码。我想让你读第一个代码,但第二个只是一个正常的访问者模式的参考代码。

我的问题是为什么访问者模式要求每个类继承VisitorsHostInterface类,该类具有虚拟函数accept();如有需要,请参阅下面的第二个代码"正常访客模式"。在我的理解中,没有必要使用accept()函数来扫描所有实例,如第一个代码,"我的测试代码"。我认为"我的测试代码"比"正常的访问者模式"更简单。请告诉我为什么访问者模式要求接受()函数到每个类?非常感谢。

(1)我的测试代码
class ClassD;
class ClassC {
public:
    ClassC(int new_value, ClassD* new_next_object) : value_(new_value), next_object_(new_next_object) {};
    void print() { std::cout << "ClassC value_ = " << value_ << std::endl; }
    int value() { return value_; }
    std::shared_ptr<ClassD> next_object(void) { return next_object_; }
private:
    int value_=0;
    std::shared_ptr<ClassD> next_object_;
};
class ClassD {
public:
    ClassD(int new_value, ClassC* new_next_object) : value_(new_value), next_object_(new_next_object) {};
    void print() { std::cout << "ClassD value_ = " << value_ << std::endl; }
    int value() { return value_; }
    std::shared_ptr<ClassC> next_object(void) { return next_object_; }
private:
    int value_=0;
    std::shared_ptr<ClassC> next_object_;
};
class VisitorFuncInterface {
public:
    virtual ~VisitorFuncInterface() = default;
    virtual void visit(ClassC* obj) = 0;
    virtual void visit(ClassD* obj) = 0;
};
class VisitorFunc : public VisitorFuncInterface {
public:
    virtual ~VisitorFunc() = default;
    void visit(ClassC* obj) {
        if (obj) {
            obj->print();
            this->visit(obj->next_object().get());
        }
    }
    void visit(ClassD* obj) {
        if (obj) {
            obj->print();
            this->visit(obj->next_object().get());
        }
    }
};
void test_visitor_without_host(void) {
    ClassD* d0 = new ClassD(0, nullptr);
    ClassC* c0 = new ClassC(1, d0);
    ClassD* d1 = new ClassD(2, c0);
    VisitorFunc v;
    v.visit(d1);
    delete d1;
}
test_visitor_without_host()的结果如下:
ClassD value_ = 2
ClassC value_ = 1
ClassD value_ = 0

(2)正常访客模式代码

class ClassA;
class ClassB;
class VisitorInterface {
public:
    virtual ~VisitorInterface() = default;
    virtual void visit(ClassA* obj) = 0;
    virtual void visit(ClassB* obj) = 0;
};
class VisitorsHostInterface {  // = visitor's host
public:
    virtual ~VisitorsHostInterface() = default;
    virtual void accept(VisitorInterface& v) = 0;
};
class VisitorsHost : public VisitorsHostInterface {
public:
    virtual ~VisitorsHost();
    void accept(VisitorInterface& v) {};
};
class ClassA : public VisitorsHostInterface {
public:
    ClassA(int new_value, ClassB* new_next_object) : value_(new_value), next_object_(new_next_object) {};
    void print() { std::cout << "ClassA value_ = " << value_ << std::endl; }
    int value() { return value_; }
    std::shared_ptr<ClassB> next_object(void) { return next_object_; }
    void accept(VisitorInterface& v) { v.visit(this); };
private:
    int value_=0;
    std::shared_ptr<ClassB> next_object_;
};
class ClassB : public VisitorsHostInterface {
public:
    ClassB(int new_value, ClassA* new_next_object) : value_(new_value), next_object_(new_next_object) {};
    void print() { std::cout << "ClassB value_ = " << value_ << std::endl; }
    int value() { return value_; }
    std::shared_ptr<ClassA> next_object(void) { return next_object_; }
    void accept(VisitorInterface& v) { v.visit(this); };
private:
    int value_=0;
    std::shared_ptr<ClassA> next_object_;
};
class Visitor : public VisitorInterface {
public:
    virtual ~Visitor() = default;
    void visit(ClassA* obj) {
        if (obj) {
            obj->print();
            this->visit(obj->next_object().get());
        }
    }
    void visit(ClassB* obj) {
        if (obj) {
            obj->print();
            this->visit(obj->next_object().get());
        }
    }
};
void test_visitor(void) {
    ClassB* b0 = new ClassB(0, nullptr);
    ClassA* a0 = new ClassA(1, b0);
    ClassB* b1 = new ClassB(2, a0);
    Visitor v;
    b1->accept(v);
    delete b1;
}
test_visitor()的结果如下:
ClassB value_ = 2
ClassA value_ = 1
ClassB value_ = 0

在您的示例中,您按值保存所有对象并知道它们的静态&动态类型。您不需要动态分派,因此您不需要有一个通用的VisitorsHostInterface基类。所需要做的就是让你的类实现一个accept函数。

然而,访问者模式最常用于不能访问被访问对象的动态类型的情况。假设你有一个vecotr<unique_ptr<Widget>>。其中许多不同的Widget子类型通过指针存储。Widget及其每一个子类必须实现虚accept函数。要获得对象的动态类型,需要执行动态分派。