设计模式--23、访问者模式

 

访问者模式是一种较为复杂的行为型设计模式,它包含访问者和被访问元素两个主要组成部分,这些被访问的元素通常具有不同的类型,且不同的访问者可以对它们进行不同的访问操作。例如处方单中的各种药品信息就是被访问的元素,而划价人员和药房工作人员就是访问者。访问者模式使得用户可以在不修改现有系统的情况下扩展系统的功能,为这些不同类型的元素增加新的操作。

      在使用访问者模式时,被访问元素通常不是单独存在的,它们存储在一个集合中,这个集合被称为“对象结构”,访问者通过遍历对象结构实现对其中存储的元素的逐个操作。

      访问者模式定义如下:

访问者模式(Visitor Pattern):提供一个作用于某对象结构中的各元素的操作表示,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式是一种对象行为型模式。

      访问者模式的结构较为复杂,其结构如图26-2所示:

 

 

 

      在访问者模式结构图中包含如下几个角色:

      ●Vistor(抽象访问者):抽象访问者为对象结构中每一个具体元素类ConcreteElement声明一个访问操作,从这个操作的名称或参数类型可以清楚知道需要访问的具体元素的类型,具体访问者需要实现这些操作方法,定义对这些元素的访问操作。

      ●ConcreteVisitor(具体访问者):具体访问者实现了每个由抽象访问者声明的操作,每一个操作用于访问对象结构中一种类型的元素。

      ●Element(抽象元素):抽象元素一般是抽象类或者接口,它定义一个accept()方法,该方法通常以一个抽象访问者作为参数。【稍后将介绍为什么要这样设计。】

      ●ConcreteElement(具体元素):具体元素实现了accept()方法,在accept()方法中调用访问者的访问方法以便完成对一个元素的操作。

      ● ObjectStructure(对象结构):对象结构是一个元素的集合,它用于存放元素对象,并且提供了遍历其内部元素的方法。它可以结合组合模式来实现,也可以是一个简单的集合对象,如一个List对象或一个Set对象。

      访问者模式中对象结构存储了不同类型的元素对象,以供不同访问者访问。访问者模式包括两个层次结构,一个是访问者层次结构,提供了抽象访问者和具体访问者,一个是元素层次结构,提供了抽象元素和具体元素。相同的访问者可以以不同的方式访问不同的元素,相同的元素可以接受不同访问者以不同访问方式访问。在访问者模式中,增加新的访问者无须修改原有系统,系统具有较好的可扩展性。

      在访问者模式中,抽象访问者定义了访问元素对象的方法,通常为每一种类型的元素对象都提供一个访问方法,而具体访问者可以实现这些访问方法。这些访问方法的命名一般有两种方式:一种是直接在方法名中标明待访问元素对象的具体类型,如visitElementA(ElementA elementA),还有一种是统一取名为visit(),通过参数类型的不同来定义一系列重载的visit()方法。当然,如果所有的访问者对某一类型的元素的访问操作都相同,则可以将操作代码移到抽象访问者类中,其典型代码如下所示:

[java] view plain copy
  1. abstract class Visitor  
  2. {  
  3.     public abstract void visit(ConcreteElementA elementA);  
  4.     public abstract void visit(ConcreteElementB elementB);  
  5.     public void visit(ConcreteElementC elementC)  
  6.     {  
  7.         //元素ConcreteElementC操作代码  
  8.     }  
  9. }  

      在这里使用了重载visit()方法的方式来定义多个方法用于操作不同类型的元素对象。在抽象访问者Visitor类的子类ConcreteVisitor中实现了抽象的访问方法,用于定义对不同类型元素对象的操作,具体访问者类典型代码如下所示:

[java] view plain copy
  1. class ConcreteVisitor extends Visitor  
  2. {  
  3.     public void visit(ConcreteElementA elementA)  
  4.     {  
  5.         //元素ConcreteElementA操作代码  
  6.     }  
  7.     public void visit(ConcreteElementB elementB)  
  8.     {  
  9.         //元素ConcreteElementB操作代码  
  10.     }  
  11. }  

      对于元素类而言,在其中一般都定义了一个accept()方法,用于接受访问者的访问,典型的抽象元素类代码如下所示:

[java] view plain copy
  1. interface Element  
  2. {  
  3.     public void accept(Visitor visitor);  
  4. }  


      需要注意的是该方法传入了一个抽象访问者Visitor类型的参数,即针对抽象访问者进行编程,而不是具体访问者,在程序运行时再确定具体访问者的类型,并调用具体访问者对象的visit()方法实现对元素对象的操作。在抽象元素类Element的子类中实现了accept()方法,用于接受访问者的访问,在具体元素类中还可以定义不同类型的元素所特有的业务方法,其典型代码如下所示:

[java] view plain copy
  1. class ConcreteElementA implements Element  
  2. {  
  3.     public void accept(Visitor visitor)  
  4.     {  
  5.         visitor.visit(this);  
  6.     }  
  7.       
  8.     public void operationA()  
  9.     {  
  10.         //业务方法  
  11.     }  
  12. }  


      在具体元素类ConcreteElementA的accept()方法中,通过调用Visitor类的visit()方法实现对元素的访问,并以当前对象作为visit()方法的参数。其具体执行过程如下:

      (1) 调用具体元素类的accept(Visitor visitor)方法,并将Visitor子类对象作为其参数

      (2) 在具体元素类accept(Visitor visitor)方法内部调用传入的Visitor对象的visit()方法,如visit(ConcreteElementA elementA),将当前具体元素类对象(this)作为参数,如visitor.visit(this);

      (3) 执行Visitor对象的visit()方法,在其中还可以调用具体元素对象的业务方法。

      这种调用机制也称为“双重分派”,正因为使用了双重分派机制,使得增加新的访问者无须修改现有类库代码,只需将新的访问者对象作为参数传入具体元素对象的accept()方法,程序运行时将回调在新增Visitor类中定义的visit()方法,从而增加新的元素访问方式。

 

思考

双重分派机制如何用代码实现?

 


      在访问者模式中,对象结构是一个集合,它用于存储元素对象并接受访问者的访问,其典型代码如下所示:

[java] view plain copy
  1. class ObjectStructure  
  2. {  
  3.     private ArrayList<Element> list = new ArrayList<Element>(); //定义一个集合用于存储元素对象  
  4.   
  5.     public void accept(Visitor visitor)  
  6.     {  
  7.         Iterator i=list.iterator();  
  8.           
  9.         while(i.hasNext())  
  10.         {  
  11.             ((Element)i.next()).accept(visitor); //遍历访问集合中的每一个元素  
  12.         }  
  13.     }  
  14.   
  15.     public void addElement(Element element)  
  16.     {  
  17.         list.add(element);  
  18.     }  
  19.   
  20.     public void removeElement(Element element)  
  21.     {  
  22.         list.remove(element);  
  23.     }  
  24. }  


      在对象结构中可以使用迭代器对存储在集合中的元素对象进行遍历,并逐个调用每一个对象的accept()方法,实现对元素对象的访问操作。

 

思考

访问者模式是否符合“开闭原则”?【从增加新的访问者和增加新的元素两方面考虑。】

转载于:https://www.cnblogs.com/snowbook/p/5207835.html

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

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

相关文章

『协议』XML-RPC 协议规格说明

为什么80%的码农都做不了架构师&#xff1f;>>> 这篇文章提供所有实现XML-RPC协议所需要的内容。 一览 XML-RPC是一个工作在因特网上的远端程序调用&#xff08;Remote Procedure Calling&#xff09;协议。 XML-RPC消息是一个HTTP-POST请求&#xff08;Request&…

Qt之QLineEdit详解(附源码)

原博客地址&#xff1a;http://blog.csdn.net/liang19890820/article/details/52044639&#xff0c;感谢原作者总结和分享。 简述 QLineEdit是一个单行文本输入框。 QLineEdit允许用户输入和编辑单行纯文本&#xff0c;提供了很多有用的编辑功能&#xff0c;包括&#xff1a;撤…

C#json数据的序列化和反序列化(将数据转换为对象或对象集合)

引用 System.Runtime.Serialization.Json 转载于:https://www.cnblogs.com/a849788087/p/5645828.html

位图(bmp)文件格式分析

from&#xff1a;https://blog.csdn.net/qingchuwudi/article/details/25785307 位图(bmp)文件格式分析 作者&#xff1a;深蓝&#xff08;由博主分享&#xff09; 一、什么是位图 计算机能以位图和矢量图格式显示图像。 1、位图(Bitmap)&#xff1a; 图像又称点阵图或光…

java 基本功 —— 内存相关

2019独角兽企业重金招聘Python工程师标准>>> 首先我们来说说内存&#xff0c;因为从内存的角度来出发来分析一些变量&#xff0c;引用或者对象的生命周期会更好理解一些。 java是一门编程语言&#xff0c;他跟C有什么不同呢&#xff1f;本质上&#xff0c;他们都是一…

DOM事件处理有三个阶段

DOM事件处理有三个阶段&#xff1a; 捕捉阶段&#xff08;capture phase&#xff09;&#xff1a;从最上层元素&#xff0c;直到最下层&#xff08;你点击的那个target&#xff09;元素。路过的所有节点都可以捕捉到该事件。命中阶段&#xff08;target phase&#xff09;&…

客户端程序自动更新(升级)的方式

from&#xff1a;https://blog.csdn.net/woaitingting1985/article/details/72954652一、C/S自动更新原理C/S程序自动升级是一个很重要的功能&#xff0c;原理其实很简单&#xff0c;一般包含两个程序一个是主程序&#xff0c;也就是除了升级功能以外的程序&#xff0c;另一个就…

怎么用源程序把ChemDraw结构复制到Word文档

在学习化学过程中&#xff0c;不可避免的会接触到各种化学结构。这个时候就需要通过绘制化学结构来进行这方面的学习和传播。ChemDraw Professional 15就可以辅助完成这方面的工作。很多的用户朋友会通过选中后复制粘贴可以将ChemDraw结构复制到Word文档中&#xff0c;但这只是…

QT串口编程的相关类(QSerialPortInfo)

QT Serial Port相关的类只有两个QSerialPortInfo(#include<QSerialPortInfo>) 和QserialPort(#include<QSerialPort>) 先来介绍QSerialPortInfo 1&#xff1a;QSerialPortInfo(#include<QSerialPortInfo>) 该类是一个串口的辅助类类&#xff0c;提供主要是提…

用jquery写一个属于自己的音乐播放器

看到一个用css3实现的CD的动画&#xff0c;演示在这儿http://codepen.io/_kieran/pen/QNRmep 突然那我就想说给自己做一个音乐播放器吧&#xff0c;说做就做。演示在https://echolsx.github.io/music/ Github传送门&#xff1a;https://github.com/EchoLsx/music 主要代码&…

MySQL 性能监控 4 大指标

【编者按】本文作者为 John Matson&#xff0c;主要介绍 mysql 性能监控应该关注的 4 大指标。 文章系国内 ITOM 管理平台 OneAPM 编译呈现。 MySQL 是什么&#xff1f; MySQL 是现而今最流行的开源关系型数据库服务器。由 Oracle 所有&#xff0c;MySQL 提供了可以免费下载的社…

【深度相机系列四】深度相机原理揭秘--结构光(iPhone X 齐刘海原理)

from&#xff1a;https://blog.csdn.net/electech6/article/details/78707839导读 结构光法&#xff1a;为解决双目匹配问题而生 深度图效果&#xff1a;结构光vs.双目 投射图案的编码方式直接编码时分复用编码空分复用编码 Kinect1原理 iPhone X原深感相机是缩小版的更强大的K…

Android倒计时工具类

为什么80%的码农都做不了架构师&#xff1f;>>> 原文地址:http://my.oschina.net/reone/blog/710003 多谢touch_ping 的回应. 原来api有这个类 android.os.CountDownTimer , 具体实现很下面的差不多. import android.content.Context; import android.os.Handler…

深度相机原理揭秘--双目立体视觉

欢迎关注计算机视觉life&#xff01;导读 为什么非得用双目相机才能得到深度&#xff1f; 双目立体视觉深度相机的工作流程 双目立体视觉深度相机详细工作原理理想双目相机成像模型极线约束图像矫正技术基于滑动窗口的图像匹配基于能量优化的图像匹配 双目立体视觉深度相机的优…

微信扫码支付模式一和模式二的区别

http://www.baidu.com/link?urlAj_xhOM5Q6rpZXkTMBPq4o0UbCO4eLq0esX8B3K2v06bkRS8F8lC4k06rv-3uZARLLTEKJHMhwzI_cdcJiHfqK&wd&eqid904bc71f000181740000000356d7d9bf https://www.zhihu.com/question/35818812/answer/66086727 知乎页面访问存在502 Bad Gateway问题…

双目视觉几何框架详解(玉米专栏8篇汇总)

一、图像坐标&#xff1a;我想和世界坐标谈谈(A) 玉米竭力用轻松具体的描述来讲述双目三维重建中的一些数学问题。希望这样的方式让大家以一个轻松的心态阅读玉米的《计算机视觉学习笔记》双目视觉数学架构系列博客。这个系列博客旨在捋顺一下已标定的双目视觉中的数学主线。数…

(原)Ubuntu14中安装GraphicsMagick

转载请注明出处&#xff1a; http://www.cnblogs.com/darkknightzh/p/5661439.html 参考网址&#xff1a; http://comments.gmane.org/gmane.comp.video.graphicsmagick.core/514 http://www.graphicsmagick.org/INSTALL-unix.html https://github.com/clementfarabet/graphics…

世界坐标系和相机坐标系,图像坐标系的关系

from&#xff1a;https://blog.csdn.net/waeceo/article/details/50580607一、四个坐标系简介和转换相机模型为以后一切标定算法的关键&#xff0c;只有这边有相当透彻的理解&#xff0c;对以后的标定算法才能有更好的理解。本人研究了好长时间&#xff0c;几乎每天都重复看几遍…

PythonOCC 3D图形库学习—创建立方体模型

Open CASCADE&#xff08;简称OCC&#xff09;平台是是一个开源的C类库&#xff0c;OCC主要用于开发二维和三维几何建模应用程序&#xff0c;包括通用的或专业的计算机辅助设计CAD系统、制造或分析领域的应用程序、仿真应用程序或图形演示工具。 PythonOCC是对Open CASCADE的封…

Struts2、SpringMVC、Servlet(Jsp)性能对比 测试 。 Servlet的性能应该是最好的,可以做为参考基准,其它测试都要向它看齐,参照...

2019独角兽企业重金招聘Python工程师标准>>> Struts2、SpringMVC、Servlet(Jsp)性能对比 测试 。 Servlet的性能应该是最好的&#xff0c;可以做为参考基准&#xff0c;其它测试都要向它看齐&#xff0c;参照它。 做为一个程序员&#xff0c;对于各个框架的性能要有…