访客设计模式示例

本文是我们名为“ Java设计模式 ”的学院课程的一部分。

在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因,并了解何时以及如何应用模式中的每一个。 在这里查看 !

目录

1.简介 2.什么是访客设计模式 3.实施访客设计模式 4.何时使用访客设计模式 5. JDK中的访问者设计模式 6.下载源代码

1引言

要了解访客设计模式,让我们重新访问“ 复合设计模式” 。 组合模式使您可以将对象组合成树形结构,以表示部分整体层次结构。

在Composite Pattern示例中,我们创建了一个由不同类型的对象组成的html结构。 现在假设我们需要在html标签中添加一个css类。 一种方法是在使用setStartTag方法添加开始标记时添加类。 但是,这种硬编码设置会给我们的代码造成僵化。

另一种方法是在父抽象HtmlTag类中添加新方法,例如addClass 。 所有子类都将重写此方法,并将提供css类。 这种方法的一个主要缺点是,如果有很多子类(将在大型html页面中显示),则在所有子类中实现此方法将变得非常昂贵且忙碌。 并假设,稍后我们需要在标签中添加另一个样式元素,我们再次需要执行相同的操作。

访客设计模式为您提供了一种在不更改元素类的情况下,在对象上添加新操作的方法,尤其是当操作经常更改时。

2.什么是访客设计模式

访客设计模式的目的是表示要对对象结构的元素执行的操作。 访问者可让您定义新操作,而无需更改其所操作元素的类。

当跨类层次结构的对象的异构集合设计操作时,Visitor模式很有用。 访客模式允许在不更改集合中任何对象的类的情况下定义操作。 为此,Visitor模式建议在一个单独的类中定义该操作,该类称为visiter类。 这将操作与其所操作的对象集合分开。 对于每个要定义的新操作,都会创建一个新的访问者类。 由于该操作将在一组对象上执行,因此访问者需要一种访问这些对象的公共成员的方法。 可以通过实施以下两个设计思想来满足此要求。

图1-访客设计模式类图

图1 –访客设计模式类图

游客

  • 为对象结构中每类ConcreteElement声明一个Visit操作。 操作的名称和签名标识了将Visit请求发送给visitor 。 这使访问者可以确定要访问的元素的具体类别。 然后,访问者可以直接通过其特定界面访问该元素。

具体访客

  • 实现Visitor声明的每个操作。 每个操作都会实现为结构中相应对象类别定义的算法片段。 ConcreteVisitor提供算法的上下文并存储其本地状态。 这种状态通常会在遍历结构期间累积结果。

元件

  • 定义一个Accept操作,将visitor作为参数。

ConcreteElement

  • 实现将visitor作为参数的Accept操作。

对象结构

  • 可以枚举其元素。
  • 可以提供一个高级界面,以允许visitor访问其元素。
  • 可以是组合或集合,例如列表或集合。

3.实施访客设计模式

为了实现Visitor设计模式,我们将使用相同的Composite Pattern代码 ,并将为其引入一些新的接口,类和方法。

实现Visitor模式需要两个重要的接口,一个Element接口,它将包含一个参数为Visitor类型的accept方法。 所有需要允许访问者访问的类都将实现此接口。 在我们的例子中, HtmlTag将实现Element接口,因为HtmlTag是所有具体html类的父抽象类,因此具体类将继承并覆盖Element接口的accept方法。

另一个重要的界面是Visitor界面; 此接口将包含带有实现Element接口的类的参数的visit方法。 还请注意,与Composite Design Pattern课程中显示的示例相反,我们在HtmlTag类中添加了两个新方法,即getStartTaggetEndTag

package com.javacodegeeks.patterns.visitorpattern;public interface Element {public void accept(Visitor visitor);
}package com.javacodegeeks.patterns.visitorpattern;public interface Visitor {public void visit(HtmlElement element);public void visit(HtmlParentElement parentElement);
}

下面的代码来自Composite Pattern示例,进行了一些更改。

package com.javacodegeeks.patterns.visitorpattern;import java.util.List;public abstract class HtmlTag implements Element{public abstract String getTagName();public abstract void setStartTag(String tag);public abstract String getStartTag();public abstract String getEndTag();public abstract void setEndTag(String tag);public void setTagBody(String tagBody){throw new UnsupportedOperationException("Current operation is not support for this object");}public void addChildTag(HtmlTag htmlTag){throw new UnsupportedOperationException("Current operation is not support for this object");}public void removeChildTag(HtmlTag htmlTag){throw new UnsupportedOperationException("Current operation is not support for this object");}public List<HtmlTag>getChildren(){throw new UnsupportedOperationException("Current operation is not support for this object");}public abstract void generateHtml();}

抽象的HtmlTag类实现Element接口。 下面的具体类将覆盖Element接口的accept方法,并调用visit方法,并将this运算符作为参数传递。 这将允许visitor方法获取该对象的所有公共成员,并对其添加新的操作。

package com.javacodegeeks.patterns.visitorpattern;import java.util.ArrayList;
import java.util.List;public class HtmlParentElement extends HtmlTag {private String tagName;private String startTag; private String endTag;private List<HtmlTag>childrenTag;public HtmlParentElement(String tagName){this.tagName = tagName;this.startTag = "";this.endTag = "";this.childrenTag = new ArrayList<>();}@Overridepublic String getTagName() {return tagName;}@Overridepublic void setStartTag(String tag) {this.startTag = tag;}@Overridepublic void setEndTag(String tag) {this.endTag = tag;}@Overridepublic String getStartTag() {return startTag;}@Overridepublic String getEndTag() {return endTag;}@Overridepublic void addChildTag(HtmlTag htmlTag){childrenTag.add(htmlTag);}@Overridepublic void removeChildTag(HtmlTag htmlTag){childrenTag.remove(htmlTag);}@Overridepublic List<HtmlTag>getChildren(){return childrenTag;}@Overridepublic void generateHtml() {System.out.println(startTag);for(HtmlTag tag : childrenTag){tag.generateHtml();}System.out.println(endTag);}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}}
package com.javacodegeeks.patterns.visitorpattern;public class HtmlElement extends HtmlTag{private String tagName;private String startTag; private String endTag;private String tagBody;public HtmlElement(String tagName){this.tagName = tagName;this.tagBody = "";this.startTag = "";this.endTag = "";}@Overridepublic String getTagName() {return tagName;}@Overridepublic void setStartTag(String tag) {this.startTag = tag;}@Overridepublic void setEndTag(String tag) {this.endTag = tag;}@Overridepublic String getStartTag() {return startTag;}@Overridepublic String getEndTag() {return endTag;}@Overridepublic void setTagBody(String tagBody){this.tagBody = tagBody;}@Overridepublic void generateHtml() {System.out.println(startTag+""+tagBody+""+endTag);}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}}

现在,具体的访问者类:我们创建了两个具体的类,一个将为所有html标记添加一个cssvisitor ,另一个将使用html标记的style属性更改标记的宽度。

package com.javacodegeeks.patterns.visitorpattern;public class CssClassVisitor implements Visitor{@Overridepublic void visit(HtmlElement element) {element.setStartTag(element.getStartTag().replace(">", " class='visitor'>"));}@Overridepublic void visit(HtmlParentElement parentElement) {parentElement.setStartTag(parentElement.getStartTag().replace(">", " class='visitor'>"));}}
package com.javacodegeeks.patterns.visitorpattern;public class StyleVisitor implements Visitor {@Overridepublic void visit(HtmlElement element) {element.setStartTag(element.getStartTag().replace(">", " style='width:46px;'>"));}@Overridepublic void visit(HtmlParentElement parentElement) {parentElement.setStartTag(parentElement.getStartTag().replace(">", " style='width:58px;'>"));}}

现在,让我们测试上面的示例。

package com.javacodegeeks.patterns.visitorpattern;public class TestVisitorPattern {public static void main(String[] args) {System.out.println("Before visitor......... \\n");HtmlTag parentTag = new HtmlParentElement("<html>");parentTag.setStartTag("<html>");parentTag.setEndTag("</html>");HtmlTag p1 = new HtmlParentElement("<body>");p1.setStartTag("<body>");p1.setEndTag("</body>");parentTag.addChildTag(p1);HtmlTag child1 = new HtmlElement("<p>");child1.setStartTag("<p>");child1.setEndTag("</p>");child1.setTagBody("Testing html tag library");p1.addChildTag(child1);child1 = new HtmlElement("<p>");child1.setStartTag("<p>");child1.setEndTag("</p>");child1.setTagBody("Paragraph 2");p1.addChildTag(child1);parentTag.generateHtml();System.out.println("\\nAfter visitor....... \\n");Visitor cssClass = new CssClassVisitor();Visitor style = new StyleVisitor();parentTag = new HtmlParentElement("<html>");parentTag.setStartTag("<html>");parentTag.setEndTag("</html>");parentTag.accept(style);parentTag.accept(cssClass);p1 = new HtmlParentElement("<body>");p1.setStartTag("<body>");p1.setEndTag("</body>");p1.accept(style);p1.accept(cssClass);parentTag.addChildTag(p1);child1 = new HtmlElement("<p>");child1.setStartTag("<p>");child1.setEndTag("</p>");child1.setTagBody("Testing html tag library");child1.accept(style);child1.accept(cssClass);p1.addChildTag(child1);child1 = new HtmlElement("<p>");child1.setStartTag("<p>");child1.setEndTag("</p>");child1.setTagBody("Paragraph 2");child1.accept(style);child1.accept(cssClass);p1.addChildTag(child1);parentTag.generateHtml();}}

上面的代码将导致以下输出:

Before visitor......... <html>
<body>
<p>Testing html tag library</p>
<p>Paragraph 2</p>
</body>
</html>After visitor....... <html style='width:58px;' class='visitor'>
<body style='width:58px;' class='visitor'>
<p style='width:46px;' class='visitor'>Testing html tag library</p>
<p style='width:46px;' class='visitor'>Paragraph 2</p>
</body>
</html>

“访问者之前……”之后的输出与“复合模式”课程中的输出相同。 后来,我们创建了两个具体的访问者,然后使用accept方法将它们添加到具体的html对象中。 输出“ After visitor…”显示给您结果,其中将css类和样式元素添加到html标记中。

请注意,Visitor Pattern的优点是我们可以在不更改其类的情况下向对象添加新操作。 例如,我们可以添加一些JavaScript函数,例如onclick或一些angularjs ng标签,而无需修改类。

4.何时使用访客设计模式

在以下情况下使用“访问者”模式:

  • 对象结构包含许多具有不同接口的对象类,并且您希望根据这些对象的具体类对这些对象执行操作。
  • 需要对对象结构中的对象执行许多不同且不相关的操作,并且您要避免使用这些操作“污染”它们的类。 访客可以通过在一个类中定义相关操作来将它们保持在一起。 当许多应用程序共享对象结构时,请使用Visitor将操作仅放在需要它们的那些应用程序中。
  • 定义对象结构的类很少更改,但是您经常想在该结构上定义新的操作。 更改对象结构类需要重新定义所有访问者的接口,这可能会导致成本高昂。 如果对象结构类经常更改,则最好在这些类中定义操作。

5. JDK中的访问者设计模式

  • javax.lang.model.element.Elementjavax.lang.model.element.ElementVisitor
  • javax.lang.model.type.TypeMirrorjavax.lang.model.type.TypeVisitor

6.下载源代码

这是“访客设计模式”的一课。 您可以在此处下载相关的源代码: VisitorPattern-Project

翻译自: https://www.javacodegeeks.com/2015/09/visitor-design-pattern.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/356885.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

报名照片审核处理工具_太浦军考|2020年文职人员报名照片审核程序,照片处理工具应该如何使用?...

考文职 找太浦 最靠谱照片处理工具使用说明01注意&#xff1a;一、本工具是报名照片审核处理工具&#xff0c;只有通过该审核工具审核通过的照片才能在注册时正常上传。照片将应用在准考证和合格证书中。二、源文件必须是标准证件数字照片&#xff0c;JPG或JPEG格式&#xff0c…

python 比赛成绩预测_Python预测NBA比赛结果

下载W3Cschool手机App&#xff0c;0基础随时随地学编程导语利用Python简单地预测一下NBA比赛结果。。。这大概就叫蹭热度吧。。。毕竟貌似今天朋友圈都在刷NBA相关的内容。。。虽然我并不能看懂。。。但这并不妨碍我瞎预测一波。。。So,以下内容纯属瞎玩&#xff0c;如有雷同&a…

适配器设计模式示例

本文是我们名为“ Java设计模式 ”的学院课程的一部分。 在本课程中&#xff0c;您将深入研究大量的设计模式&#xff0c;并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因&#xff0c;并了解何时以及如何应用模式中的每一个。 在这里查看 &#xff01; 目录 …

cesium鼠标控制键盘_Cesium中级教程3 - Camera - 相机(摄像机)

CameraCesiumJS中的Camera控制场景的视图。有很多方法可以操作Camera&#xff0c;如旋转(rotate)、缩放(zoom)、平移(pan)和飞到目的地(flyTo)。CesiumJS有鼠标和触摸事件用来处理与Camrea的交互&#xff0c;还有API来以编程方式操作摄像机。了解如何使用Camera API和自定义相机…

windows下统一mysql编码_mysql5.7 windows7编码统一utf-8

查看mysql数据编码登录mysql服务&#xff0c;查看mysql数据库默认的编码mysql> show variables like character%;---------------------------------------------------------------------------| Variable_name | Value |------------------------------------------------…

python读取配置文件失败原因_python读取配置文件报keyerror-文件路径不正确导致的错误...

- 在其他模块使用反射读取配置文件报错&#xff0c;但是在反射模块中读取GetData.check_list又是正确的反射模块如下&#xff1a;# get_data.pyfrom API_AUTO.p2p_project_7.tools import project_pathimport pandas as pdfrom API_AUTO.p2p_project_7.tools.read_config impor…

备忘录设计模式示例

本文是我们名为“ Java设计模式 ”的学院课程的一部分。 在本课程中&#xff0c;您将深入研究大量的设计模式&#xff0c;并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因&#xff0c;并了解何时以及如何应用模式中的每一个。 在这里查看 &#xff01; 目录 …

打印机一直显示正在删除不掉怎么办?

1、停止打印服务&#xff0c;按WinR键打开运行对话框&#xff0c;然后输入“services.msc ” 打开任务管理。 找到“Print Spooler”&#xff0c;先停止该服务。 按WinR键打开运行对话框&#xff0c;然后输入“Spool” 回车打开“spool” 文件夹&#xff0c;打开“PRINTERS”文…

java 并发 面试_Java 并发基础常见面试题总结

1. 什么是线程和进程?1.1. 何为进程?进程是程序的一次执行过程&#xff0c;是系统运行程序的基本单位&#xff0c;因此进程是动态的。系统运行一个程序即是一个进程从创建&#xff0c;运行到消亡的过程。在 Java 中&#xff0c;当我们启动 main 函数时其实就是启动了一个 JVM…

javafx动画_JavaFX:创建Sprite动画

javafx动画到目前为止&#xff0c;尽管我的大多数文章都涉及JavaFX属性和绑定&#xff0c;但是今天我想写一讲我也致力于JavaFX运行时的另一部分&#xff1a;动画API。 在本文中&#xff0c;我将解释如何在JavaFX中编写自定义动画&#xff0c;以及如何使用这种方法为Sprite动画…

FZU Problem 2238 Daxia Wzc's problem

Daxia在2016年5月期间去瑞士度蜜月,顺便拜访了Wzc,Wzc给他出了一个问题&#xff1a; Wzc给Daxia等差数列A(0),告诉Daxia首项a和公差d; 首先让Daxia求出数列A(0)前n项和,得到新数列A(1); 然后让Daxia求出数列A(1)前n项和,得到新数列A(2); 接着让Daxia求出数列A(2)前n项和,得到新…

生成器设计模式示例

本文是我们名为“ Java设计模式 ”的学院课程的一部分。 在本课程中&#xff0c;您将深入研究大量的设计模式&#xff0c;并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因&#xff0c;并了解何时以及如何应用模式中的每一个。 在这里查看 &#xff01; 目录 …

【转】从 ArcGIS for Desktop 发布地图服务

原文链接&#xff1a;http://resources.arcgis.com/zh-CN/help/tutorials/01z300000007000000.htm 本教程的目的是将地图服务直接从 ArcGIS for Desktop 发布到 ArcGIS for Server 中。本教程与名为“在 ArcMap 中准备您的 Web 地图”的上一教程类似&#xff0c;需要使用 ArcGI…

java 模块化osgi_OSGi简介–模块化Java

java 模块化osgiOSGi联盟是这种搁浅的管理机构&#xff0c;它始于1999年。其最初目标是为网络设备创建开放搁浅。 基于此思想&#xff0c;此规范也针对Java引入。 Eclipse在Java中是第一个。 他们于2004年6月推出了基于OSGi的Eclipse IDE。 OSGi是在Java中定义动态模块的方法。…

Train Problem I hdu 1022(栈)

http://acm.split.hdu.edu.cn/showproblem.php?pid1022 题意&#xff1a;给出火车的进站与出站顺序&#xff0c;判断是否可以按照给出的出站顺序出站。 #include <iostream> #include <stdio.h> #include <string.h> #include <string> #include <…

Spring数据和Redis

本文是我们学院课程的一部分&#xff0c;标题为Redis NoSQL键值存储 。 这是Redis的速成班。 您将学习如何安装Redis并启动服务器。 此外&#xff0c;您将在Redis命令行中乱七八糟。 接下来是更高级的主题&#xff0c;例如复制&#xff0c;分片和集群&#xff0c;同时还介绍了…

史上最全的SpringMVC学习笔记

SpringMVC学习笔记---- 一、SpringMVC基础入门&#xff0c;创建一个HelloWorld程序 1.首先&#xff0c;导入SpringMVC需要的jar包。 2.添加Web.xml配置文件中关于SpringMVC的配置<!--configure the setting of springmvcDispatcherServlet and configure the mapping-->&…

shader weaver_Oracle通过邀请Weaver和Chin推动JavaFX向前发展

shader weaver昨天&#xff0c;我发布了愚人节帖子&#xff0c;内容涉及加入NASA协助探索红色大行星。 那篇文章与事实相距不远……美国宇航局开发的技术的所有细节都是100&#xff05;准确的。 哎呀&#xff0c;即使我辞职也是事实&#xff01; 唯一不正确的部分是我将加入的公…

mysql快速上手3

上一章给大家说的是数据库的视图&#xff0c;存储过程等等操作&#xff0c;这章主要讲索引&#xff0c;以及索引注意事项&#xff0c;如果想看前面的文章&#xff0c;url如下&#xff1a; mysql快速上手1mysql快速上手2索引简介 索引是对数据库表中一个或多个列&#xff08;例如…

python图像锐化_Python图像处理介绍--图像模糊与锐化

欢迎关注 “小白玩转Python”&#xff0c;发现更多 “有趣”引言在之前的文章中&#xff0c;我们讨论了边缘检测内核。在本文我们将讨论如何在图像上应用模糊与锐化内核&#xff0c;将这些内核应用到彩色图像上&#xff0c;同时保留核心图像。一如既往&#xff0c;我们从导入所…