访问者模式

在GOF的《设计模式:可复用面向对象软件的基础》一书中对访问者模式是这样说的:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化。该模式的目的是要把处理从数据结构分离出来。访问者模式让增加新的操作很容易,因为增加新的操作就意味着增加一个新的访问者。访问者模式将有关的行为集中到一个访问者对象中。现在再来说说我之前经历过的那个项目。

是基于Windows Shell开发的一个项目,在一个容器中存储了很多的Shell Items,同时定义了对Items的操作,由于项目一直都在进行后期扩展,对Items的操作在后期都需要进行扩展的;而现在的做法是,定义一个操作类,该操作类中定义了一个集合,该集合存放Items,在该操作类中扩展对应的操作方法。现在想想如果使用访问者模式也是可以的,由于Items集合是固定的,当需要扩展集合的操作时,只需要添加对应的访问者即可。

UML类图

Visitor(访问者):为该对象结构中ConcreteElement的每一个类声明一个Visit操作。该操作的名字和特征标识了发送Visit请求给该访问者的那个类。这使得访问者可以确定正被访问元素的具体的类。这样访问者就可以通过该元素的特定接口直接访问它。
ConcreteVisitor(具体访问者):实现每个由Visitor声明的操作。每个操作实现本算法的一部分,而该算法片段乃是对应于结构中对象的类。ConcreteVisitor为该算法提供了上下文并存储它的局部状态。这一状态常常在遍历该结构的过程中累积结果。
Element(元素):定义一个Accept操作,它以一个访问者为参数。
ConcreteElement(具体元素):实现Accept操作,该操作以一个访问者为参数。
ObjectStructure(对象结构):能够枚举它的元素,同时提供一个高层的接口以允许该访问者访问它的元素。

使用场合

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

代码实现

 #include <iostream>
#include <vector>
using namespace std; class ConcreteElementA;
class ConcreteElementB; class Visitor
{
public:
virtual void VisitConcreteElementA(ConcreteElementA *pElementA) = ;
virtual void VisitConcreteElementB(ConcreteElementB *pElementB) = ;
}; class ConcreteVisitor1 : public Visitor
{
public:
void VisitConcreteElementA(ConcreteElementA *pElementA);
void VisitConcreteElementB(ConcreteElementB *pElementB);
}; void ConcreteVisitor1::VisitConcreteElementA(ConcreteElementA *pElementA)
{
// 现在根据传进来的pElementA,可以对ConcreteElementA中的element进行操作
} void ConcreteVisitor1::VisitConcreteElementB(ConcreteElementB *pElementB)
{
// 现在根据传进来的pElementB,可以对ConcreteElementB中的element进行操作
} class ConcreteVisitor2 : public Visitor
{
public:
void VisitConcreteElementA(ConcreteElementA *pElementA);
void VisitConcreteElementB(ConcreteElementB *pElementB);
}; void ConcreteVisitor2::VisitConcreteElementA(ConcreteElementA *pElementA)
{
// ...
} void ConcreteVisitor2::VisitConcreteElementB(ConcreteElementB *pElementB)
{
// ...
} // Element object
class Element
{
public:
virtual void Accept(Visitor *pVisitor) = ;
}; class ConcreteElementA : public Element
{
public:
void Accept(Visitor *pVisitor);
}; void ConcreteElementA::Accept(Visitor *pVisitor)
{
pVisitor->VisitConcreteElementA(this);
} class ConcreteElementB : public Element
{
public:
void Accept(Visitor *pVisitor);
}; void ConcreteElementB::Accept(Visitor *pVisitor)
{
pVisitor->VisitConcreteElementB(this);
} // ObjectStructure类,能枚举它的元素,可以提供一个高层的接口以允许访问者访问它的元素
class ObjectStructure
{
public:
void Attach(Element *pElement);
void Detach(Element *pElement);
void Accept(Visitor *pVisitor); private:
vector<Element *> elements;
}; void ObjectStructure::Attach(Element *pElement)
{
elements.push_back(pElement);
} void ObjectStructure::Detach(Element *pElement)
{
vector<Element *>::iterator it = find(elements.begin(), elements.end(), pElement);
if (it != elements.end())
{
elements.erase(it);
}
} void ObjectStructure::Accept(Visitor *pVisitor)
{
// 为每一个element设置visitor,进行对应的操作
for (vector<Element *>::const_iterator it = elements.begin(); it != elements.end(); ++it)
{
(*it)->Accept(pVisitor);
}
} int main()
{
ObjectStructure *pObject = new ObjectStructure; ConcreteElementA *pElementA = new ConcreteElementA;
ConcreteElementB *pElementB = new ConcreteElementB; pObject->Attach(pElementA);
pObject->Attach(pElementB); ConcreteVisitor1 *pVisitor1 = new ConcreteVisitor1;
ConcreteVisitor2 *pVisitor2 = new ConcreteVisitor2; pObject->Accept(pVisitor1);
pObject->Accept(pVisitor2); if (pVisitor2) delete pVisitor2;
if (pVisitor1) delete pVisitor1;
if (pElementB) delete pElementB;
if (pElementA) delete pElementA;
if (pObject) delete pObject; return ;
}

总结

访问者模式的基本思想如下:首先拥有一个由许多对象构成的对象结构,就是上面代码中的ObjectStructure,这些对象的类都拥有一个Accept方法用来接受访问者对象;访问者是一个接口,它拥有一个Visit方法,这个方法对访问到的对象结构中不同类型的元素做出不同的操作;在对象结构的一次访问过程中,我们遍历整个对象结构,对每一个元素都实施Accept方法,在每一个元素的Accept方法中回调访问者的Visit方法,从而使访问者得以处理对象结构的每一个元素。我们就可以针对对象结构设计不同的访问者类来完成不同的操作。

设计模式中经常说的一句话是:发现变化并封装之。是否采用访问者模式,就要看“变化”是什么。访问者模式中,“变化”是具体访问者,其次是对象结构;但是,如果具体元素也会发生改变,就万万不能使用访问者模式,因为这样“牵一发而动全身”,后期的维护性就太差了。

C++设计模式——访问者模式的更多相关文章

  1. .NET设计模式访问者模式

    一.访问者模式的定义: 表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作. 二.访问者模式的结构和角色: 1.Visitor 抽象访问者角色,为该 ...

  2. C#设计模式-访问者模式

    一. 访问者(Vistor)模式 访问者模式是封装一些施加于某种数据结构之上的操作.一旦这些操作需要修改的话,接受这个操作的数据结构则可以保存不变.访问者模式适用于数据结构相对稳定的系统, 它把数据结 ...

  3. JAVA 设计模式 访问者模式

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

  4. 深入浅出设计模式——访问者模式(Visitor Pattern)

    模式动机 对于系统中的某些对象,它们存储在同一个集合中,且具有不同的类型,而且对于该集合中的对象,可以接受一类称为访问者的对象来访问,而且不同的访问者其访问方式有所不同,访问者模式为解决这类问题而诞生 ...

  5. java设计模式---访问者模式

      Java深入到一定程度,就不可避免的碰到设计模式这一概念,了解设计模式,将使自 己对java中的接口或抽象类应用有更深的理解.设计模式在java的中型系统中应用广 泛,遵循一定的编程模式,才能使自 ...

  6. 设计模式 -- 访问者模式(Visitor)

    写在前面的话:读书破万卷,编码如有神--------------------------------------------------------------------主要内容包括: 初识访问者模 ...

  7. Java设计模式—访问者模式

    原文地址:http://www.cnblogs.com/java-my-life/archive/2012/06/14/2545381.html 总结的太棒啦,导致自己看了都不想总结了...... 在 ...

  8. C#设计模式——访问者模式(Visitor Pattern)

    一.概述由于需求的改变,某些类常常需要增加新的功能,但由于种种原因这些类层次必须保持稳定,不允许开发人员随意修改.对此,访问者模式可以在不更改类层次结构的前提下透明的为各个类动态添加新的功能.二.访问 ...

  9. Java设计模式-访问者模式(Visitor)

    访问者模式把数据结构和作用于结构上的操作解耦合,使得操作集合可相对自由地演化.访问者模式适用于数据结构相对稳定算法又易变化的系统.因为访问者模式使得算法操作增加变得容易.若系统数据结构对象易于变化,经 ...

随机推荐

  1. Scrapy安装报错

    python3 pip 安装Scrapy在win10 安装报错error: Microsoft Visual C++ 14.0 is required. Get it with "Micro ...

  2. Linux中什么是动态网站环境及如何部署

    当谈论起网站时,我们可能听说过静态和动态这两个词,但却不知道它们的含义,或者从字面意思了解一些却不知道它们的区别. 这一切可以追溯到网站和网络应用程序,Web应用程序是一个网站,但很多网站不是Web应 ...

  3. Filter过滤要登录的页面(重要)

    一.为什么要写过滤器,过滤页面? 本人做了一个网站,目前还在开发.做过滤器的目的就是为了要过滤一些页面必需要用户登录之后才能看,主页什么的可以随便看,一旦涉及到要发布或评论什么信息,就必须要过滤用户的 ...

  4. 图论专题1考试Problem1

    Problem 1. bricksInput file: bricks.inOutput file: bricks.outTime limit: 1 secondjyb 在BUAA 天天被大神虐,所以 ...

  5. 基于MySQL的Activiti6引擎创建

    整个activiti6的搭建都是在spring boot2之上的,首先贴一下pom: <dependencies> <!-- 这是activiti需要的最基本的核心引擎 --> ...

  6. 洛谷 p1090 合并果子

    https://www.luogu.org/problemnew/show/P1090 优先队列的经典题目 体现了stl的优越性 #include<bits/stdc++.h> using ...

  7. java 中的基本数据类型

    1,  变量 Java是强类型语言, 对于每一种数据都定义了类型,基本数据类型分为数值型,字符型,布尔型.数值型又分为了整型和浮点型. 整型又分为byte, int, short long. 浮点型又 ...

  8. SQLServer 中多行数据合并成一行数据(一个字段)

    需求:有四行数据,如下: 1.苹果 2.橘子 3.桃子 4.波罗 合并成一个字段:苹果,橘子,桃子,波罗: 需求明确之后,先弄点测试数据,上代码: --创建一个临时表 Create table #te ...

  9. MYSQL IN 出现的慢查询问题

    IN = https://blog.csdn.net/solmyr_biti/article/details/54293492 https://www.cnblogs.com/wxw16/p/6105 ...

  10. python学习日记(isinstance和issubclass)

    isinstance(obj,cls)检查是否obj是否是类 cls 的对象 class Foo(object): pass obj = Foo() isinstance(obj, Foo) issu ...