访客模式 无痕模式 区别

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

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

目录

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

1引言

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

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

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

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

2.什么是访客设计模式

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

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

图1 –访客设计模式类图

游客

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

具体访客

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

元件

  • 定义将visitor作为参数的Accept操作。

ConcreteElement

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

对象结构

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

3.实施访客设计模式

为了实现Visitor Design Pattern,我们将使用相同的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

访客模式 无痕模式 区别

访客模式 无痕模式 区别_访客设计模式示例相关推荐

  1. 访客模式 无痕模式 区别_模式:访客模式

    访客模式 无痕模式 区别 问候, 这周我们放开所有代数的内容,然后集中精力 面向对象编程的全部内容. Java声称支持OO,因此 为什么不使用它? 在本周的文章中,我们将讨论一下何时 以及为什么要应用 ...

  2. 访客模式 无痕模式 区别_旧访客设计模式的新生活

    访客模式 无痕模式 区别 介绍 访客 [1.2]是众所周知的经典设计模式. 有很多资源对其进行了详细说明. 在不深入研究实现的情况下,我将简要提醒一下该模式的概念,解释其优点和缺点,并提出一些可以使用 ...

  3. 访客模式 无痕模式 区别_访客设计模式

    访客模式 无痕模式 区别 我猜想很多人都知道来访者设计模式,这在<四人帮的设计模式:可重用的面向对象软件的元素>一书中有描述. 模式本身不是很复杂(随着许多设计模式的发展): 我很久以来就 ...

  4. 访客模式 无痕模式 区别_行为设计模式:访客

    访客模式 无痕模式 区别 行为设计模式的最后一个模式将是访客模式. 当我们希望能够在不更改类的情况下为对象结构的类定义新操作时,使用访问者模式. 想象一下执行对api的http请求的软件的场景. 大多 ...

  5. 移动端浏览器隐私模式/无痕模式使用本地存储localStorage/sessionStorage的问题

    2019独角兽企业重金招聘Python工程师标准>>> 开发H5 webapp时经常需要使用本地存储,如localStorage和sessionStorage存储一些数据,相比最多能 ...

  6. 原型模式的应用场景_前端常用设计模式

    求关注 前端常见的设计模式主要有以下几种:1. 单例模式2. 工厂模式3. 策略模式4. 代理模式5. 观察者模式6. 模块模式7. 构造函数模式8. 混合模式 单例模式 这种设计模式的思想是确保一个 ...

  7. 设计模式示例_责任链设计模式示例

    设计模式示例 本文是我们名为" Java设计模式 "的学院课程的一部分. 在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们. 您将了解模式如此重要的原因 ...

  8. quirks 模式是什么?它和 standards 模式有什么区别_什么是二级分销模式

    现在的营销模式在逐渐的演变着,我们可以揣测到当今营销多样化的模式上阵,其效果各有不同,这也是网络发展到今天的产物.微信的发展,聚集了大量的用户,这也为商家提供了良好的机会,作为营销的主战场,更成为大家 ...

  9. 装饰着模式示例_装饰器设计模式示例

    装饰着模式示例 本文是我们名为" Java设计模式 "的学院课程的一部分. 在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们. 您将了解模式如此重要的原 ...

最新文章

  1. 5G NGC — 关键技术 — CUPS
  2. Struts2--DomainModel接收参数---使用广泛!!!
  3. linux递归创建文件夹_Python中并发请求创建文件夹带来的线程安全问题
  4. Neither spark.yarn.jars nor spark.yarn.archive is set
  5. python 的几个内置函数(lambda ,zip, filter, map, reduce )用法
  6. apache pulsar_Apache Pulsar:分布式Pub-Sub消息系统
  7. 读书笔记--SQL必知必会03--排序检索数据
  8. CyclicBarrier-同步辅助类
  9. 推荐一款配有强大数据管理和可视化ETL的BI工具
  10. Log4j2进阶使用(按大小时间备份日志)
  11. 全面拥抱云原生应用研发的拐点已经到来
  12. bzoj 3367: [Usaco2004 Feb]The Big Game 球赛(DP)
  13. JavaScript 系列笔记(一)数据类型
  14. SVN服务器端安装过程出现“Custom action InstallWMISchemaExecute failed:无法启动服务,原因可能是已被禁用或与其相关联的设备没有启动。”
  15. Windows数据类型
  16. ffmpeg 音乐循环_Android使用FFmpeg(四)--ffmpeg实现音频播放(使用AudioTrack进行播放)
  17. war包的打包与解压
  18. 1688商品类目API接口-(item_cat_get-获得1688商品类目接口)
  19. 电阻电容电感PCB封装真实尺寸大小
  20. 注册表 关闭打印机服务器,win7系统添加打印机无Print Spooler服务无注册表的解决方法...

热门文章

  1. 深大数据库系统实验3——DATABASE SOFTWARE练习实验
  2. 不止音乐与露营——聊聊极狐汽车的微信生态营销
  3. PANDA pipeline的安装与使用-安装(1)
  4. Java 获取当前年,前几年(之前年),后几年(之后年)
  5. 重磅!五大电力央企“一把手”华山论剑深谈数字化转型
  6. 接口测试用例设计实践总结
  7. 自然的密码---36幅由算法生成的六芒星图像
  8. 依赖注入依赖注入容器
  9. VS 2017 解决 C2001错误 常量中有换行符
  10. 信息安全导论 实验一 古典密码学