谈C++17里的Visitor模式logger

Visitor模式包含两个主要的对象:Visitable对象和Vistor对象。此外,作为将被操作的对象,在Visitor模式中也包含Visited对象。

一个Visitable对象,即管理者,可能包含一系列形态各异的元素(Visited),它们可能在Visitable中具有复杂的结构关系(但也可以是某种单纯的容纳关系,如一个简单的vector)。Visitable一般会是一个复杂的容器,负责解释这些关系,并以一种标准的逻辑遍历这些元素。当Visitable对这些元素进行遍历时,它会将每个元素提供给Visitor令其能够访问该Visited元素。

这样一种编程模式就是VisitorPattern。

为了能够观察每个元素,因此实际上必然会有一个约束:所有的可被观察的元素具有共同的基类Visited。

所有的Visitors必须派生于Visitor才能提供给Visitable.accept(visitor&)接口。

namespacehicc::util{structbase_visitor{virtual~base_visitor(){}};structbase_visitable{virtual~base_visitable(){}};templateclassvisitor:publicbase_visitor{public:usingreturn_t=ReturnType;usingvisited_t=std::unique_ptr;virtualreturn_tvisit(visited_tconst&visited)=0;};templateclassvisitable:publicbase_visitable{public:virtual~visitable(){}usingreturn_t=ReturnType;usingvisitor_t=visitor;virtualreturn_taccept(visitor_t&guest)=0;};}//namespacehicc::util场景以一个实例来说,假设我们正在设计一套矢量图编辑器,在画布(Canvas)中,可以有很多图层(Layer),每一图层包含一定的属性(例如填充色,透明度),并且可以有多种图元(Element)。图元可以是Point,Line,Rect,Arc等等。

为了能够将画布绘制在屏幕上,我们可以有一个Screen设备对象,它实现了Visitor接口,因此画布可以接受Screen的访问,从而将画布中的图元绘制到屏幕上。

如果我们提供Printer作为观察者,那么画布将能够把图元打印出来。

如果我们提供Document作为观察者,那么画布将能够把图元特性序列化到一个磁盘文件中去。

如果今后需要其它的行为,我们可以继续增加新的观察者,然后对画布及其所拥有的图元进行类似的操作。

对于结构层级复杂的情况,要善于使用对象嵌套与递归能力,避免反复编写相似逻辑。

我们以矢量图编辑器的一部分为示例进行实现,采用了前面给出的基础类模板。

出于简化的理由基础图元没有进行层次化,而是平行地派生于drawable。

namespacehicc::dp::visitor::basic{structgroup:publicdrawable,publichicc::util::visitable{MAKE_DRAWABLE(group)usingdrawable_t=std::unique_ptr;usingdrawables_t=std::unordered_map;drawables_tdrawables;voidadd(drawable_t&&t){drawables.emplace(t->id(),std::move(t));}return_taccept(visitor_t&guest)override{for(autoconst&[did,dr]:drawables){guest.visit(dr);UNUSED(did);}}};structlayer:publicgroup{MAKE_DRAWABLE(layer)//more:attrs,...};}在groupclass中已经实现了visitable接口,它的accept能够接受访问者的访问,此时图元组group会遍历自己的所有图元并提供给访问者。

默认时guest会访问visitedconst&形式的图元,也就是只读方式。

图层至少具有group的全部能力,所以面对访问者它的做法是相同的。图层的属性部分(mask,overlay等等)被略过了。

画布包含了若干图层,所以它同样应该实现visitable接口:

namespacehicc::dp::visitor::basic{structcanvas:publichicc::util::visitable{usinglayer_t=std::unique_ptr;usinglayers_t=std::unordered_map;layers_tlayers;voidadd(draw_idid){layers.emplace(id,std::make_unique(id));}layer_t&get(draw_idid){returnlayers[id];}layer_t&operator[](draw_idid){returnlayers[id];}virtualreturn_taccept(visitor_t&guest)override{//hicc_debug("[canva]visitingfor:%s",to_string(guest).c_str());for(autoconst&[lid,ly]:layers){ly->accept(guest);}return;}};}其中,add将会以默认参数创建一个新图层,图层顺序遵循向上叠加方式。get和[]运算符能够通过正整数下标访问某一个图层。但是代码中没有包含图层顺序的管理功能,如果有意,你可以添加一个std::vector的辅助结构来帮助管理图层顺序。

现在我们来回顾画布-图层-图元体系,accept接口成功地贯穿了整个体系。

是时候建立访问者们了

这两者实现了简单的访问者接口:

namespacehicc::dp::visitor::basic{structscreen:publichicc::util::visitor{return_tvisit(visited_tconst&visited)override{hicc_debug("[screen][draw]for:%s",to_string(visited.get()).c_str());}friendstd::ostream&operator<<(std::ostream&os,screenconst&){returnos<<"[screen]";}};structprinter:publichicc::util::visitor{return_tvisit(visited_tconst&visited)override{hicc_debug("[printer][draw]for:%s",to_string(visited.get()).c_str());}friendstd::ostream&operator<<(std::ostream&os,printerconst&){returnos<<"[printer]";}};}hicc::to_string是一个简易的串流包装,它做如下的核心逻辑:

templateinlinestd::stringto_string(Tconst&t){std::stringstreamss;ss<

voidtest_visitor_basic(){usingnamespacehicc::dp::visitor::basic;canvasc;staticdraw_idid=0,did=0;c.add(++id);//addedonegraph-layerc[1]->add(std::make_unique(++did));c[1]->add(std::make_unique(++did));c[1]->add(std::make_unique(++did));screenscr;c.accept(scr);}输出结果应该类似于这样:

---BEGINOFtest_visitor_basic----------------------09/14/2100:33:31[debug]:[screen][draw]for:09/14/2100:33:31[debug]:[screen][draw]for:09/14/2100:33:31[debug]:[screen][draw]for:

THE END
1.计算机图形学基础基于三原色原理,分别控制红色、绿色、蓝色三个通道的亮度,可以混合出各种颜色。 每个像素点 都用一个三元组(R,G,B)表示,每个分量使用0-255之间的整数表示表示该通道的亮度。 颜色空间转灰度空间。 得到图形轮廓,节省算力和存储空间。 线性插值法: 双线性插值法: 图形的线性变化:缩放变化、剪切变换、旋转变换。https://www.jianshu.com/p/8558d3117892
2.C++矢量图形库系列(1)——矢量图形库乱谈(转)园荐2006-04-29 15:57 ? 位图和矢量图是计算机图形中的两大概念,这两种图形都被广泛应用到出版,印刷,互联网[如flash和svg]等各个方面,他们各有优缺点,两者各自的好处几乎是无法相互替代的,所以,长久以来,矢量跟位图在应用中一直是平分秋色。 位图[bitmap],也叫做点阵图,删格图象,像素图,简单的说,就是最小单位...https://recomm.cnblogs.com/blogpost/3885144?page=1
3.打算做一个开源的矢量绘图软件小四的海市蜃楼自知做一个堪用的矢量绘图软件是个非常艰巨的事情,不过还是打算用一些业余时间把这件事情做了,对自己以往掌握的知识,也是一个总结。 编译好的可执行程序 程序0.01版本源代码在这里可以下载 UCanCode Form++ (C++ 国产,强大,贵,到处做广告) MicroDraw C++ (国产,专业) ...http://www.cppblog.com/cugdj/archive/2008/01/29/42140.html
4.C++BuilderXE7硬汉嵌入式论坛C++ Builder 如何实现显示矢量图,未解决 armfly 2022-2-3 01442 armfly 2022-2-3 23:13 收集一些C++ Builder的坛子,供大家学习 armfly 2022-2-2 31919 armfly 2022-2-2 21:42 请问C++builder XE7 可以设置代码补全功能吗? Dellg7 2022-2-2 01463 Dellg7 2022-2-2 09:51 Delphi C++Builder RAD ...https://www.armbbs.cn/forum.php?mod=forumdisplay&fid=46
5.基于C++的K线图绘制工具KLineChart基于C++实现的矢量图工具 基于VS2010实现矢量图工具,如矢量图的编辑、转换、选择、拖动等,编译无错误。 上传者:zengxiaobing301时间:2019-07-18 网络拓扑图绘制(C++) 在某个开源网站下载的,分享之。用c++编写的绘制网络拓扑图的软件,基本功能都有! 上传者:zerotom时间:2011-01-15 ...https://www.iteye.com/resource/baita96-11058922
6.[PDF]下载C++Templates中文版PDF电子书by范德沃德CorelDRAW是一款功能强大的矢量图绘图软件,本书以由浅入深的方式介绍最新版本CorelDRAW X6中文版软件的使用。CorelDRAW是用于印刷、多媒体制作及联机制图的应用程序,无论是设计人员,还是为印刷出版制作图形的专家或者为多媒体制作图形的设计者,都可以使用CorelDRAW来制作专业品质的作品。本书内容既有基础知识的介绍,... ...http://www.51ebooks.com/book/c-templates%E4%B8%AD%E6%96%87%E7%89%88-11400-pdf.html
7.矢量图和位图相比,哪一项是矢量图的优点()A. 矢量图放大后不会失真,不会出现马赛克;而位图的清晰度是由分辨率决定的。 B. 位图图像是连续色调图像,可以有效地表现阴影和颜色的细节层次;矢量图相对位图的过渡则显得有些生硬。 C. 位图的数据量比矢量图的数据量小 D. 矢量图可以使用PS来修改,位图不可以 查看完整题目与答案 【单选题】串行接口RS232...https://www.shuashuati.com/ti/ec36d1120db140e081c1bd883c10659b.html?fm=bdbds18e5a89affe7a9dba5dc2944b20e4d24
1.C++计算机视觉各种背景建模文章浏览阅读186次。C++计算机视觉-各种背景建模对常见的差分法,codebook,均值方差法和混合高斯法进行详细介绍,同时描述去除噪声区域的方案https://blog.csdn.net/l35633/article/details/143508172
2.图像处理系列(C++)——形态学图像处理系列(C++)—— 形态学图像形态学操作 基于形状的一系列图像处理操作的合集 主要是基于集合论基础上的形态学数学 形态学有四个基本操作 腐蚀 膨胀 开闭 大家好,欢迎来到IT知识分享网。 图像形态学操作 – 基于形状的一系列图像处理操作的合集,主要是基于集合论基础上的形态学数学。 https://yundeesoft.com/108747.html
3.Draw这是一个绘图软件 包含了基本的绘图工具以及滤镜、马赛克、旋转、缩放的实现点赞(0) 踩踩(0) 反馈 访问所需:1 积分 电信网络下载 访问申明(访问视为同意此申明) 1.在网站平台的任何操作视为已阅读和同意网站底部的版权及免责申明 2.部分网络用户分享TXT文件内容为网盘地址有可能会失效(此类多为视频教程,如...https://cpp.code.coder100.com/index/index/content/id/61417
4.C++编程语言logo图标矢量图office办公软件:Word图标logo矢量图 C++编程语言logo图标矢量图 Apple Pay标志矢量图 热门标签 LOGO设计矢量素材标志设计元素球队队徽住宅设计插画欣赏别墅设计NBA球队标志公寓设计插画作品欣赏插画作品人物插画绘画作品海报设计标志设计包装设计广告欣赏PNG图标网站设计创意广告优秀包装设计画册设计名片设计VI设计字体设计插画平面广...https://www.sj33.cn/sc/logo/dzhy/it/202010/54405.html
5.如何生产矢量图软件的软件零代码企业数字化知识站要生产矢量图软件的软件,可以选择"编程语言和框架"、"图形库和工具"、"用户界面设计"、"测试和优化"、以及"发布和维护"这些步骤。选择适当的编程语言和框架是生产矢量图软件的关键,例如,C++、Java、Python 等流行编程语言都能够支持高性能的图形处理。C++ 有强大的性能和控制能力,适合开发高效的矢量图处理引擎。使用...https://www.jiandaoyun.com/blog/article/320908/
6.C++编程语言logo全站资源免费下载限时优惠VIP包年68元,包月20元 下载提示'无法安全下载'请点此查看设置方法 素材分类: 矢量IT类标志所需点数:0点 关键词: C++编程语言logo图标矢量图,AI格式,C++,编程语言,logo图标 下载文件 电信下载点1 电信下载点2 特别说明:本站所有资源仅供学习与参考,请勿用于商业用途,如有侵犯您的版权,请...http://www.sccnn.com/shiliangbiaozhiVI/shiliangITleibiaozhi/20201004-268571.html
7.从新手到老手之Qt学习历程一个QPicture是一个可以完美地缩放,旋转和裁剪的矢量图。QPictrue类存储的图象是一系列绘图命令而不是一些象素的数据。它支持SVG(W3C's Scalable Vector Graphics)XML格式的输入与输出。 一个QPrinter表现为一台物理打印机。在Windows中,绘画命令被送到Windows打印引擎来使用已安装的驱动。在Unix中,输出PostScript并送...https://mobile.51cto.com/symbian-268768.htm
8.C++教程其它相关资料下载前一个月工厂反馈摄像头的图像信号在矢量示波器中打转(说明一下:矢量示波器可以将CVBS信号中的,行同步信号,场同步信号,色同步信号等转换成矢量图输出,如果同步信号不稳适配其它的显示产品就会出问题,具体应该是接收过程中丢包或中断,如果接收端做同步处理应该会解决的,知道的发信息留言。),检查锁定在无 ...https://download.eeworld.com.cn/download/froglucky/256748
9.PS和AI将图片转成矢量图PS软件做的图都是位图,可以导出AI格式,但是不可能做成矢量图的。放大后会有马塞克,可以把分辨率调高一点,做出来的位图会清晰一些,但放大或缩小后,图片还是为失真,表现为像素点。 CoreIDRAW是矢量软件,这个软件做出来的图是矢量的。 还有AI 也是矢量软件。这个软件做出来的图也是矢量的。 https://blog.mimvp.com/article/14131.html
10.编辑出版商PUB元数据C++Aspose.PUBPub 文件包含文本以及位图和矢量图形数据。 发布者元数据是描述 PUB 文档的属性(信息)。它们是标准属性,如发布者、标题、最后作者、组织、URL、语言和其他类似信息。还有一些数据是在处理文件后自动生成的,例如文件大小或上次编辑时间。此有用信息与文档一起存储。 使用我们尖端的 C++ 解决方案来发现元数据分析的...https://products.aspose.com/pub/zh-hant/cpp/metadata/
11.Raphael一个用于在网页中绘制矢量图形的Javascript库jqueryRaphael是一个用于在网页中绘制矢量图形的 Javascript 库。它使用 SVG W3C 推荐标准和 VML 作为创建图形的基础,你可以通过 JavaScript 操作 DOM 来轻松创建出各种复杂的柱状图、饼图、曲线图等各种图表,还可以绘制任意形状的图形,可以进行图表或图像的裁剪和旋转等复杂操作。 https://www.jb51.net/article/33099.htm