C++实现Visitor访问者模式 & 头文件循环包含的问题
2021-03-26 15:25
标签:fine 数据 避免 struct java 解耦 margin return sign 翻译:https://springframework.guru/gang-of-four-design-patterns/visitor-pattern/ “Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.” 表示要在对象结构的元素上进行的操作。Visitor模式允许你在不修改被操作对象的前提下给被操作对象增加新的操作。 将数据与行为分开,这样后续增加数据对象、或增加行为都很简单,属于行为模式中的一种,注意与Bridge桥接模式进行对比。 下面是一个邮件客户端配置应用,mail client configurator application。首先定义Element类: 上面的MailClient定义了收发邮件相关的函数,并定义了accept()函数,该函数以一个Visitor对象为入参。下面定义MailClient的三个子类: OperaMailClient: 另外两个:SquirrelMailClient ZimbraMailClient与之类似,省略。 在上面的代码中,重点看子类实现的accept(Visitor)函数,在该函数中入参为一个Visitor,而在函数中调用Visitor的visit()函数时,我们又将Element本身作为参数传递给Visitor。对于具体的Element类,在运行时Element函数的accept调用Visitor函数,而Visitor类会对具体的Element类调用visit()函数,这称为double dispatch。但是Java、C++并不支持double dispatch。Visitor模式可以让我们模拟double dispatch。 对于每个Element类,我们把对它的相关操作封装在Visitor子类的visit()函数中,即:将相关的操作从Element类中移出。这样做的好处在于:实现了操作与数据本身的解耦,以后添加一个操作,或添加一个Element都只改变其相关代码即可。 Visitor的接口定义如下: 其子类LinuxMailClientVisitor实现如下: 在具体的Visitor中,实现对数据相关的操作,如上面的visit()方法。在上述代码中,不同的Visitor子类的可以访问同一个具体的Element,如OperaMailClient类;而不同的Element类可以被同一个Visitor类访问。因此,一个具体的操作依赖于visitor以及具体的Element类(double dispatch)。 测试代码: 输出: Visitor模式是最为复杂的模式之一。一个Visitor可以访问不同对象结构,例如使用组合模式的对象组合、或一个继承树。在合适的情景下使用Visitor模式可以简化代码结构,并容易扩展。 对比,两者长的很像。。。 参考:https://blog.csdn.net/centurionAX/article/details/107984778 情景: 在类A需要调用类B的方法,而在类B中也需要调用类A的方法,在类A的头文件中会#include B,而在类B的头文件中会#include A,从而引起头文件的循环包含。在解析代码时,先将 解决方法: 在A B互相包含时,在头文件中使用类的前置声明,而不是头文件;在.cpp文件中使用#include包含需要调用方法的类的头文件,这样就不会产生编译错误。 C++实现Visitor访问者模式 & 头文件循环包含的问题 标签:fine 数据 避免 struct java 解耦 margin return sign 原文地址:https://www.cnblogs.com/zyk1113/p/13686847.html桥接模式
定义:
适用:
类图:
例子
#ifndef _MAIL_CLIENT_H_
#define _MAIL_CLIENT_H_
#include string>
#include
#ifndef _OPERA_MAIL_CLIENT_H_
#define _OPERA_MAIL_CLIENT_H_
#include "MailClient.h"
class OperaMailClient : public MailClient
{
public:
OperaMailClient();
~OperaMailClient();
virtual void sendMail(vectorstring> mailInfo) override;
virtual void receiveMail(vectorstring> mailInfo) override;
virtual bool accept(MailClientVisitor *visitor) override;
};
#endif // !_OPERA_MAIL_CLIENT_H_
#include "OperaMailClient.h"
#include
#ifndef _MAIL_CLIENT_VISITOR_H_
#define _MAIL_CLIENT_VISITOR_H_
#include "OperaMailClient.h"
#include "SquirrelMailClient.h"
#include "ZimbraMailClient.h"
//class OperaMailClient;
//class SquirrelMailClient;
//class ZimbraMailClient;
class MailClientVisitor
{
public:
MailClientVisitor(){}
virtual ~MailClientVisitor(){}
virtual void visit(OperaMailClient* mailClient) = 0;
virtual void visit(SquirrelMailClient* mailClient) = 0;
virtual void visit(ZimbraMailClient* mailClient) = 0;
};
#endif // !_MAIL_CLIENT_VISITOR_H_
#ifndef _LINUX_MAIL_CLIENT_VISITOR_H_
#define _LINUX_MAIL_CLIENT_VISITOR_H_
#include "MailClientVisitor.h"
class LinuxMailClientVisitor : public MailClientVisitor
{
public:
LinuxMailClientVisitor();
~LinuxMailClientVisitor();
virtual void visit(OperaMailClient* mailClient) override;
virtual void visit(SquirrelMailClient* mailClient) override;
virtual void visit(ZimbraMailClient* mailClient) override;
};
#endif // !_LINUX_MAIL_CLIENT_VISITOR_H_
#include "LinuxMailClientVisitor.h"
#include
#include
总结:
访问者模式与桥接模式
头文件循环包含问题
A.h
中的内容展开;A.h
的开头包含了B.h
,再将B.h
在A.h
的开头展开;B.h
的开头虽然又包含了A.h
,但是由于此时A.h
已经被包含过一次,在#pragma once
指令或者头文件宏的约束下会避免将Parent.h
再次展开,因此编译时会提示XXX未定义的错误。
文章标题:C++实现Visitor访问者模式 & 头文件循环包含的问题
文章链接:http://soscw.com/index.php/essay/68180.html