详解C++设计模式编程中对访问者模式的运用

访问者模式(visitor),表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式适用于数据结构相对稳定的系统。它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化。访问者模式的目的是要把处理从数据结构分离出来。很多系统可以按照算法和数据结构分开,如果这样的系统有比较稳定的数据结构,又有易于变化的算法的话,使用访问者模式就是比较合适的,因为访问者模式使得算法操作的增加变得容易。反之,如果这样的系统的数据结构对象易于变化,经常要有新的数据对象增加进来,就不适合使用访问者模式。

访问者模式的优点就是增加新的操作很容易,因为增加新的操作就意味着增加一个新的访问者。访问者模式将有关的行为集中到一个访问者对象中。通常concreteVisitor可以单独开发,不必跟concreteElement写在一起。访问者的缺点其实也就是使增加新的数据结构变得困难了。

结构图:

访问者模式基本示例代码

访问者模式 visitor.h、concreteVisitor.h、element.h、concreteElement.h、objectStructure.h

客户端 visitorApp.cpp

访问者模式

visitor.h
/************************************************************************
 * description: 为该对象结构中ConcreteElement的每一个类声明一个visit操作
 * remark:
************************************************************************/
#ifndef _VISITOR_H_
#define _VISITOR_H_
class concreteElementA;
class concreteElementB;
class visitor
{
public:
 visitor(){};
 virtual ~visitor(){};
 virtual void visitConcreteElementA(concreteElementA* pConcreteElementA) = 0;
 virtual void visitConcreteElementB(concreteElementB* pConcreteElementB) = 0;
};
#endif// _VISITOR_H_

concreteVisitor.h

/************************************************************************
 * description: 具体访问者,实现每个由visitor声明的操作。每个操作实现算法
    的一部分,而该算法片断乃是对应于结构中对象的类
 * remark:
************************************************************************/
#ifndef _CONCRETE_VISITOR_H_
#define _CONCRETE_VISITOR_H_
#include "visitor.h"
#include <iostream>
using namespace std;
class concreteVisitor1 : public visitor
{
public:
 concreteVisitor1(){};
 ~concreteVisitor1(){};
 virtual void visitConcreteElementA(concreteElementA* pConcreteElementA)
 {
  cout << "concreteElementA被concreteVisitor1访问" << endl;
 }
 virtual void visitConcreteElementB(concreteElementB* pConcreteElementB)
 {
  cout << "concreteElementB被concreteVisitor1访问" << endl;
 }
}; 

class concreteVisitor2 : public visitor
{
public:
 concreteVisitor2(){};
 ~concreteVisitor2(){};
 virtual void visitConcreteElementA(concreteElementA* pConcreteElementA)
 {
  cout << "concreteElementA被concreteVisitor2访问" << endl;
 }
 virtual void visitConcreteElementB(concreteElementB* pConcreteElementB)
 {
  cout << "concreteElementB被concreteVisitor2访问" << endl;
 }
};
#endif// _CONCRETE_VISITOR_H_

element.h

/************************************************************************
 * description: 定义一个accept操作,它以一个访问者为参数
 * remark:
************************************************************************/
#ifndef _ELEMENT_H_
#define _ELEMENT_H_
class visitor;
class element
{
public:
 element(){};
 virtual ~element(){};
 virtual void accept(visitor* pVisitor) = 0;
};
#endif// _ELEMENT_H_

concreteElement.h

#ifndef _CONCRETE_ELEMENT_H_
#define _CONCRETE_ELEMENT_H_
#include "element.h"
#include <iostream>
using namespace std;
class concreteElementA : public element
{
public:
 concreteElementA(){};
 ~concreteElementA(){};
 // 充分利用双分派技术,实现处理与数据结构的分离
 virtual void accept(visitor* pVisitor)
 {
  if (NULL != pVisitor)
  {
   pVisitor->visitConcreteElementA(this);
  }
 }
 // 其他的相关方法
 void operationA()
 {
  cout << "具体元素A的其他相关方法" << endl;
 }
};
class concreteElementB : public element
{
public:
 concreteElementB(){};
 ~concreteElementB(){};
 // 充分利用双分派技术,实现处理与数据结构的分离
 virtual void accept(visitor* pVisitor)
 {
  if (NULL != pVisitor)
  {
   pVisitor->visitConcreteElementB(this);
  }
 }
 // 其他的相关方法
 void operationB()
 {
  cout << "具体元素B的其他相关方法" << endl;
 }
};
#endif// _CONCRETE_ELEMENT_H_

objectStructure.h

/************************************************************************
 * description: 枚举元素,可以提供一个高层的接口以允许访问者访问它的元素
 * remark:
************************************************************************/
#ifndef _OBJECT_STRUCTURE_H_
#define _OBJECT_STRUCTURE_H_
#include "element.h"
#include "visitor.h"
#include <list>
using namespace std;
class objectStructure
{
public:
 void attach(element* pElement)
 {
  m_list.push_back(pElement);
 }
 void detach(element* pElement)
 {
  m_list.remove(pElement);
 }
 void accept(visitor* pVisitor)
 {
  list<element*>::iterator Iter;
  for (Iter = m_list.begin(); Iter != m_list.end(); ++Iter)
  {
   if (NULL != *Iter)
   {
    (*Iter)->accept(pVisitor);
   }
  }
 }
private:
 list<element*> m_list;
};
#endif// _OBJECT_STRUCTURE_H_

客户端

visitorApp.cpp

// visitorApp.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "objectStructure.h"
#include "concreteElement.h"
#include "concreteVisitor.h"
void freePtr(void* vptr)
{
 if (NULL != vptr)
 {
  delete vptr;
  vptr = NULL;
 }
}
int _tmain(int argc, _TCHAR* argv[])
{
 objectStructure* pObject = new objectStructure();
 if (NULL != pObject)
 {
  element* pElementA = new concreteElementA();
  element* pElementB = new concreteElementB();
  pObject->attach(pElementA);
  pObject->attach(pElementB);
  concreteVisitor1* pVisitor1 = NULL;
  pVisitor1 = new concreteVisitor1();
  concreteVisitor2* pVisitor2 = NULL;
  pVisitor2 = new concreteVisitor2();
  pObject->accept(pVisitor1);
  pObject->accept(pVisitor2);
  system("pause");
  freePtr(pVisitor2);
  freePtr(pVisitor1);
  freePtr(pElementB);
  freePtr(pElementA);
  freePtr(pObject);
 }
 return 0;
}

使用访问者模式的优点和缺点

访问者模式有如下的优点:

  • 访问者模式使得增加新的操作变得很容易。如果一些操作依赖于一个复杂的结构对象的话,那么一般而言,增加新的操作会很复杂。而使用访问者模式,增加新的操作就意味着增加一个新的访问者类,因此,变得很容易。
  • 访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中。
  • 访问者模式可以跨过几个类的等级结构访问属于不同的等级结构的成员类。迭代子只能访问属于同一个类型等级结构的成员对象,而不能访问属于不同等级结构的对象。访问者模式可以做到这一点。
  • 积累状态。每一个单独的访问者对象都集中了相关的行为,从而也就可以在访问的过程中将执行操作的状态积累在自己内部,而不是分散到很多的节点对象中。这是有益于系统维护的优点。

访问者模式有如下的缺点:

  • 增加新的节点类变得很困难。每增加一个新的节点都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作。
  • 破坏封装。访问者模式要求访问者对象访问并调用每一个节点对象的操作,这隐含了一个对所有节点对象的要求:它们必须暴露一些自己的操作和内部状态。不然,访问者的访问就变得没有意义。由于访问者对象自己会积累访问操作所需的状态,从而使这些状态不再存储在节点对象中,这也是破坏封装的。

访问者模式的适用场景:

  • 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
  • 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。Vi s i t o r 使得你可以将相关的操作集中起来定义在一个类中。当该对象结构被很多应用共享时,用Vi s i t o r 模式让每个应用仅包含需要用到的操作。
  • 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。
时间: 2016-03-15

php设计模式 Visitor 访问者模式

复制代码 代码如下: <?php /** * 访问者模式 * * 表示一个作用于某对象结构中的各元素的操作,可以在不改变各元素的类的前提下定义作用于这些元素的新操作 * */ abstract class Visitor { abstract public function visitCroncreteElementA($element); abstract public function visitCroncreteElementB($element); } class ConcreteVis

JAVA设计模式之访问者模式详解

在阎宏博士的<JAVA与模式>一书中开头是这样描述访问者(Visitor)模式的: 访问者模式是对象的行为模式.访问者模式的目的是封装一些施加于某种数据结构元素之上的操作.一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变. 分派的概念 变量被声明时的类型叫做变量的静态类型(Static Type),有些人又把静态类型叫做明显类型(Apparent Type):而变量所引用的对象的真实类型又叫做变量的实际类型(Actual Type).比如: 复制代码 代码如下: List lis

Python设计模式之单例模式实例

注:使用的是Python 2.7. 一个简单实现 复制代码 代码如下: class Foo(object):    __instance = None    def __init__(self):        pass    @classmethod    def getinstance(cls):        if(cls.__instance == None):            cls.__instance = Foo()        return cls.__instance

学习php设计模式 php实现访问者模式(Visitor)

访问者模式表示一个作用于某对象结构中各元素的操作.它可以在不修改各元素类的前提下定义作用于这些元素的新操作,即动态的增加具体访问者角色. 访问者模式利用了双重分派.先将访问者传入元素对象的Accept方法中,然后元素对象再将自己传入访问者,之后访问者执行元素的相应方法. 访问者模式多用在聚集类型多样的情况下.在普通的形式下必须判断每个元素是属于什么类型然后进行相应的操作,从而诞生出冗长的条件转移语句.而访问者模式则可以比较好的解决这个问题.对每个元素统一调用$element->accept($v

实例讲解iOS应用的设计模式开发中的Visitor访问者模式

为了方便向大家展示,先给出简短的定义: 访问者模式(Visitor),表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作. 紧接着,给出其类结构图. 访问者模式适用于数据结构相对稳定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作结合可以相对自由地演化. 访问者模式的目的是要把处理从数据结构分离出来.很多系统可以按照算法和数据结构分开,如果这样的系统有比较稳定的数据结构,又有易于变化的算法的话,使用访问者模式就是比较合适的,

详解Java设计模式编程中的访问者模式

定义:封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作. 类型:行为类模式 类图: 例子: 例如,思考一下添加不同类型商品的购物车,当点击结算的时候,它计算出所有不同商品需付的费用.现在,计算逻辑即为计算这些不同类型商品的价格.或者说通过访问者模式我们把此逻辑转移到了另外一个类上面.让我们实现这个访问者模式的例子. 为了实现访问者模式,最先需要做的是创建能够被添加到购物车中代表不同类型商品(itemElement)的类. ItemElement

轻松掌握python设计模式之访问者模式

本文实例为大家分享了python访问者模式代码,供大家参考,具体内容如下 """访问者模式""" class Node(object): pass class A(Node): pass class B(Node): pass class C(A, B): pass class Visitor(object): def visit(self, node, *args, **kwargs): meth = None ""&quo

C++设计模式之访问者模式

前言 这是23+1(简单工厂模式)之中的最后一个了--访问者模式.访问者模式也是一个比较麻烦的设计模式.我也没有实战经验,对于访问者模式的理解完全来自GOF的<设计模式:可复用面向对象软件的基础>,而这篇文章就是根据对这本书的理解而写出来的.在读<设计模式:可复用面向对象软件的基础>的时候,让我想起自己做过的一个项目,该项目虽然没有使用访问者模式,但是,今天理解了该模式,如果使用该模式对之前做过的项目进行重构,将是一个不错的想法. 访问者模式 在GOF的<设计模式:可复用面向

轻松掌握php设计模式之访问者模式

访问者模式解决的问题 在我们的代码编写过程当中,经常需要对一些类似的对象添加一些的代码,我们以一个计算机对象打印组成部分为例来看下: /** * 抽象基类 */ abstract class Unit { /** *获取名称 */ abstract public function getName(); } /** * Cpu类 */ class Cpu extends Unit { public function getName() { return 'i am cpu'; } } /** *

举例讲解设计模式中的访问者模式在Java编程中的运用

访问者(Visitor)模式:封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作.访问者模式的结构图如下: 通过上图可以看到他有如下角色: 抽象访问者(Visitor)角色:定义接口,声明一个或多个访问操作. 具体访问者(ConcreteVisitor)角色:实现抽象访问者所声明的接口,也就是抽象访问者所声明的各个访问操作. 抽象元素(Visitable)角色:声明一个接受操作,接受一个访问者对象作为一个参数. 具体元素结点(Concret

浅析设计模式中的代理模式在C++编程中的运用

由遇到的问题引出代理模式 至少在以下集中情况下可以用代理模式解决问题: 创建开销大的对象时候,比如显示一幅大的图片,我们将这个创建的过程交给代理去完成,GoF 称之为虚代理(Virtual Proxy): 为网络上的对象创建一个局部的本地代理,比如要操作一个网络上的一个对象(网络性能不好的时候,问题尤其突出),我们将这个操纵的过程交给一个代理去完成,GoF 称之为远程代理(Remote Proxy): 对对象进行控制访问的时候,比如在 Jive 论坛中不同权限的用户(如管理员.普通用户等)将获得

C#设计模式之Visitor访问者模式解决长隆欢乐世界问题实例

本文实例讲述了C#设计模式之Visitor访问者模式解决长隆欢乐世界问题.分享给大家供大家参考,具体如下: 一.理论定义 访问者模式 提供了 一组 集合 对象 统一的 访问接口,适合对 一个集合中的对象,进行逻辑操作,使 数据结构  和 逻辑结构分离. 二.应用举例 需求描述:暑假来啦!三个小伙子组团,开车来 长隆欢乐世界玩. 每个人想玩的项目都不一样, 旅游者 1   想玩:十环过山车,龙卷风暴,梦幻旋马 旅游者 2   想玩:空中警察,欢乐摩天轮,超级水战 旅游者 3   想玩:四维影院,垂

java编程中自动拆箱与自动装箱详解

什么是自动装箱拆箱 基本数据类型的自动装箱(autoboxing).拆箱(unboxing)是自J2SE 5.0开始提供的功能. 一般我们要创建一个类的对象实例的时候,我们会这样: Class a = new Class(parameter); 当我们创建一个Integer对象时,却可以这样: Integer i = 100; (注意:不是 int i = 100; ) 实际上,执行上面那句代码的时候,系统为我们执行了:Integer i = Integer.valueOf(100); (感谢@

浅谈Java编程中string的理解与运用

一,"=="与equals() 运行以下代码,如何解释其输出结果? public class StringPool { public static void main(String args[]) { String s0="Hello"; String s1="Hello"; String s2="He"+"llo"; System.out.println(s0==s1);//true System.out

Java编程中的构造函数详细介绍

本文主要是为新手.对java语言感兴趣的人和那些没有系统学习过java基础知识的人进行一个总结,在文章中对构造函数进行了较为详细的说明和讨论,也包含了我个人对于java面向对象中构造函数的一些看法.希望走在java学习道路上的同行者可以有一个较为清晰的认知和理解.当然仅为个人观点,水平有限,不足之处,还请大家多多指出,互相交流学习. 1.构造函数的概念 很多java新手谈到构造函数就会犯晕,我们先来看看什么是构造函数. 首先,构造函数是函数的一种特殊形式,特殊在哪里?构造函数中不需要定义返回类型

Java编程中实现Condition控制线程通信

java中控制线程通信的方法 1.传统的方式:利用synchronized关键字来保证同步,结合wait(),notify(),notifyAll()控制线程通信.不灵活. 2.利用Condition控制线程通信,灵活. 3.利用管道pipe进行线程通信,不推荐 4.利用BlockingQueue控制线程通信 本文就讲解利用Condition控制线程通信,非常灵活的方式. Condition类是用来保持Lock对象的协调调用. 对Lock不了解的可以参考:Java线程同步Lock同步锁代码示例

java编程中实现调用js方法分析

本文实例讲述了java编程中实现调用js方法.分享给大家供大家参考,具体如下: /* * 加载脚本引擎,并在java中调用js方法 */ public void test2() { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("javascript"); try { String str="2&1"

java编程中字节流转换成字符流的实现方法

java编程中字节流转换成字符流的实现方法 import java.io.*; /*readLine方法是字符流BufferReader类中的方法 * 而键盘录入的方法是字节流InputStream的方法 * 那么能不能将字节流转成字符流再使用字符流缓冲区中的readLine方法呢? * * InputStreamReader类是字节流转向字符流的桥梁.(它本身是一个字符流所以在构造时接受一个字节流) * * */ public class TransStreamDemo { public st