设计模式--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,一经查实,立即删除!

相关文章

C#串口SerialPort常用属性方法

SerialPort(): //属性 .BaudRate;获取或设置波特率 .BytesToRead;得到 接收到数据的字节数 .BytesToWrites;得到送往串口的字节数 .DataBits;获取或设置数据位 .IsOpen;获取一个值&#xff0c;判断串口是否打开 .Pariy;获取或设置校验位 .PortName;串口名称 .ReadBufferSize;获…

NTFS文件系统的简述

NTFS文件系统的设计思想基于稳定性、和安全性并支持大容量存储设备的文件系统&#xff1a;1.它提供日志可以增加文件系统的容错率&#xff0c;可以有效的保护系统的安全。NTFS是一个可恢复的文件系统。在NTFS分区上即使强制关机后&#xff0c;一般也不需要运行CHKDSK命令修复磁…

Rxjava基础

现在很多Android App的开发开始使用Rxjava&#xff0c;但是Rxjava以学习曲线陡峭著称&#xff0c;入门有些困难。经过一段时间的学习和使用&#xff0c;这里来介绍一下我对Rxjava的理解。 说到Rxjava首先需要了解的两个东西&#xff0c;一个是Observable&#xff08;被观察者&a…

『协议』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;撤…

POJ 1323 Game Prediction#贪心

(&#xff5e;&#xffe3;▽&#xffe3;)&#xff5e;* //既然是求最少能胜几次 //说明对方是要尽可能让我输 //但为了避免浪费&#xff0c;对方会用比我的牌大的牌中的最小pip的牌来击败我 #include<iostream> #include<cstdio> #include<cstring> #inclu…

qt学习之键盘事件( keyPressEvent)

//最近一直忙于做驱动&#xff0c;对底层东西很是好奇&#xff0c;好奇键盘是 怎么区分每个键值的&#xff0c;又是怎么响应的&#xff01;因此&#xff0c;就有了下面这些代码//环境windows 工具qt 语言c//在主窗体类中声明键盘响应函数 void keyPressEvent(QKeyEvent * event…

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; 图像又称点阵图或光…

汇付 支付,痛苦的接入过程

有文档&#xff0c;但是&#xff0c;写文档的人明白&#xff0c;看文档的人很有难度。 没有SDK&#xff0c;要自已写。 然后&#xff0c;钱的流入流出都必须经过虚拟钱包&#xff0c;提现还要绑取现卡&#xff0c;这个我也能理解&#xff0c;不能理解的是&#xff0c;订单退款&…

随笔分类 - HALCON学习例程中文详解

from: https://www.cnblogs.com/chita/category/563492.html随笔分类 - HALCON学习例程中文详解HALCON学习例程中文详解跟我学机器视觉-HALCON学习例程中文详解-测量圆环脚宽间距摘要: 跟我学机器视觉-HALCON学习例程中文详解-测量圆环脚宽间距* This example program demonstr…

WinCE6 如何去掉控制面板中的应用?

在WINCE600/PUBLIC/WCESHELLFE/OAK/FILES/wceshellfe.bib把对应的cpl 干掉例如区域设置 好像是2个 ; CESYSGEN IF WCESHELLFE_MODULES_INTLPintlp.cpl $(_FLATRELEASEDIR)/intlp.cpl NK SH ; CESYSGEN ENDIF ; CESYSGEN IF WCESHELLFE_MODULES_INTLLintll.cpl $(_FLATRELEASEDI…

软件自动更新解决方案及QT实现

from&#xff1a;https://blog.csdn.net/hulinhulin/article/details/46839107软件自动更新解决放案及QT实现...11 文件的版本控制-XML.22 更新程序的实现...22.1 界面设置...22.2 程序功能...32.2.1 下载网络数据...32.2.2 XML文件的分析...62.2.3 下载XML文件的DownLoadXML函…

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;但这只是…

网络流(最大流) HDU 1565 方格取数(1) HDU 1569 方格取数(2)

HDU 1565 方格取数(1)给你一个n*n的格子的棋盘&#xff0c;每个格子里面有一个非负数。从中取出若干个数&#xff0c;使得任意的两个数所在的格子没有公共边&#xff0c;就是说所取的数所在的2个格子不能相邻&#xff0c;并且取出的数的和最大。 Input 包括多个测试实例&#…

python学习 第一篇 基础

上周报名了reboot python 课程&#xff0c;终于下决心要把python 搞好了&#xff0c;希望自己能坚持下来&#xff0c;并得到自己想要的成绩#coding:utf-8 #呵呵 #print hello world #xhello world #print x #xraw_input(hello world) #print x #int #print 23 #print 12*3 #pri…

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

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