Visitor 访问者模式(行为型模式)

动机(Motivation)在软件构造过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法),如果直接在基类中做这样的修改,将会给子类带来繁重的变更负担,甚至破坏原有设计。

如果在不变更类层次结构的前提下,在运行时更加需要透明地为类层次结构上的各个类活动添加新的操作,从而避免上述问题?

意图(Intent)

表示一个作用于某种对象结构中各元素的操作。它可以在不改变各元素的类的前提下定义作用于这些元素的新操作。——《设计模式》GoF

示例代码

    public abstract class Shape
{
public abstract void Draw();
//问题:由于Shape中新增了MoveTo方法,其各个子类将不得不随之改变
public abstract void MoveTo(Point point);
} public class Rectangle : Shape
{
public override void Draw()
{
//...
}
} public class Circle : Shape
{
public override void Draw()
{
//...
}
} public class Line : Shape
{
public override void Draw()
{
//...
}
}

为了不改变各子类:

    public abstract class Shape
{
public abstract void Draw(); //预料到将来肯能会引入新的操作
public abstract void Accept(ShapeVisitor visitor);
} public abstract class ShapeVisitor
{
public abstract void Visit(Rectangle shape);
public abstract void Visit(Circle shape);
public abstract void Visit(Line shape);
} public class MyVisitor : ShapeVisitor
{
public override void Visit(Rectangle shape)
{
//增加对Rectangle的操作
} public override void Visit(Circle shape)
{
//增加对Circle的操作
} public override void Visit(Line shape)
{
//增加对Line的操作
}
} public class Rectangle : Shape
{
public override void Draw()
{
//...
} public override void Accept(ShapeVisitor visitor)
{
visitor.Visit(this);//调用Visit(Rectangle shape)
}
} public class Circle : Shape
{
public override void Draw()
{
//...
} public override void Accept(ShapeVisitor visitor)
{
visitor.Visit(this);//调用Visit(Circle shape)
}
} public class Line : Shape
{
public override void Draw()
{
//...
} public override void Accept(ShapeVisitor visitor)
{
visitor.Visit(this);//调用Visit(Line shape)
}
}

客户端调用:

        static void Main(string[] args)
{
ShapeVisitor visitor=new MyVisitor();
Line line=new Line();
line.Accept(visitor); Rectangle rectangle=new Rectangle();
rectangle.Accept(visitor);
}

结构(Structure)

Visitor模式的几个要点

  • Visitor模式通过对所谓双重分发(double dispatch)来实现在不更改Element层次结构的前提下,在运行时透明地为类层次结构上的各个类动态添加新的操作。
  • 所谓双重分发即Visitor模式中间包括了两个多态分发(注意其中的多态机制);第一个为Accept方法的多态辨析;第二个为Visit方法的多态辨析。
  • Visitor模式的最大缺点在于扩展类层次结构(增加新的Element子类),会导致Visitor类的改变。因此Visitor模式适用于“Element类层次结构稳定,而其中操作却经常面临频繁改动”。

转载请注明出处:

作者:JesseLZJ
出处:http://jesselzj.cnblogs.com

设计模式23:Visitor 访问者模式(行为型模式)的更多相关文章

  1. php设计模式(一):简介及创建型模式

    我们分三篇文章来总结一下设计模式在PHP中的应用,这是第一篇创建型模式. 一.设计模式简介 首先我们来认识一下什么是设计模式: 设计模式是一套被反复使用.容易被他人理解的.可靠的代码设计经验的总结. ...

  2. FactoryMethod工厂方法模式(创建型模式)

    1.工厂方法模式解决的问题 现在有一个抽象的游戏设施建造系统,负责构建一个现代风格和古典风格的房屋和道路. 前提:抽象变化较慢,实现变化较快(不稳定) 整个抽象的游戏设施建造系统相对变化较慢,本例中只 ...

  3. Prototype原型模式(创建型模式)

    1.原型模式解决的问题 现在有一个抽象的游戏设施建造系统,负责构建一个现代风格和古典风格的房屋和道路. 前提:抽象变化较慢,实现变化较快(不稳定) 整个抽象的游戏设施建造系统相对变化较慢,本例中只有一 ...

  4. 设计模式(Java版)-创建型模式之简单工厂模式

    前言:这段时间在学习设计模式,本人也是小菜一枚(所以写的如果有错误的地方请大大们给予指出).这个东西也是我一直想学习的,从点点滴滴做起,记录下自己每天的领悟! 一.工厂模式的动机 在软件系统中,经常面 ...

  5. C#面向对象设计模式纵横谈——2.Singleton 单件(创建型模式)

    一:模式分类 从目的来看: 创建型(Creational)模式:负责对象创建. 结构型(Structural)模式:处理类与对象间的组合. 行为型(Behavioral)模式:类与对象交互中的职责分配 ...

  6. .NET设计模式(7):创建型模式专题总结(Creational Pattern)(转)

    概述 创建型模式,就是用来创建对象的模式,抽象了实例化的过程.它帮助一个系统独立于如何创建.组合和表示它的那些对象.本文对五种常用创建型模式进行了比较,通过一个游戏开发场景的例子来说该如何使用创建型模 ...

  7. .NET设计模式(7):创建型模式专题总结(Creational Pattern)

    ):创建型模式专题总结(Creational Pattern)    创建型模式专题总结(Creational Pattern) --.NET设计模式系列之七 Terrylee,2006年1月 转载: ...

  8. 设计模式(五):PROTOTYPE原型模式 -- 创建型模式

    1.定义 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 2.适用场景 原型模式的主要思想是基于现有的对象克隆一个新的对象出来,一般是有对象的内部提供克隆的方法,通过该方法返回一个对 ...

  9. 设计模式(二): BUILDER生成器模式 -- 创建型模式

    1.定义 将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式. 2.适用场景 1. 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式 ...

  10. 设计模式(十四):Command命令模式 -- 行为型模式

    1.概述         在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来 ...

随机推荐

  1. canvas之太阳系效果

    星球 变量名 公转周期 光色 暗色 水星 Mercury 87.70 #a69697 #5c3e40 金星 Venus 224.701.70 #c4bbac #1f1315 地球 Earth 365. ...

  2. Java死锁以及命令检测

    Java每个对象都有一把锁,当前进程使用对象锁1,没有释放该锁,又想要去获取另一把对象锁2,而对象锁2被另外一个线程持有,没有释放,这就很容易出现死锁 1.死锁实例 public class Dead ...

  3. xhtml和html的区别

    1.XHTML要求正确嵌套 错误:<p>XHTML文档<strong>与HTML的主要区别</p></strong> 正确:<p>XHTML ...

  4. Running command-line BLAST

    Ubuntu安装BLAST 2014-02-09 10:45:03|  分类: Linux/Ubuntu|举报|字号 订阅     下载LOFTER我的照片书  |     very easy! su ...

  5. 深入浅出 Java Concurrency (14): 锁机制 part 9 读写锁 (ReentrantReadWriteLock) (2)

      这一节主要是谈谈读写锁的实现. 上一节中提到,ReadWriteLock看起来有两个锁:readLock/writeLock.如果真的是两个锁的话,它们之间又是如何相互影响的呢? 事实上在Reen ...

  6. Linux配置Oracle 11g自动启动

    http://www.cnblogs.com/edwardcmh/archive/2012/05/11/2495671.html 安装完毕Oracle 11g每次都得手动启动 | 停止数据库(dbst ...

  7. node全局变量process属性值(mac环境)

    任意新建一个js文件,只需一行代码: console.dir(process); 保存该文件后执行,即可得到process变量的属性值列表: { title: 'node', version: 'v0 ...

  8. ChannelHandler,ChannelHandlerContext,ChannelPipeline

    本小节一起学习一下ChannelHandler,ChannelHandlerContext,ChannelPipeline这三个Netty常用的组件,不探究它们的底层源码,我们就简单的分析一下用法 首 ...

  9. OpenLayers 3 之 切换图层控件

    OpenLayers 3 之 切换图层控件 openlayers 3中并没有默认的图层切换控件,GitHub中有一个项目实现了我们需要的控件-------- ol3-layerswitcher . 可 ...

  10. Spring2.5那些事之基于AOP的方法级注解式日志配置

    在日常开发中经常需要在代码中加入一些记录用户操作日志的log语句,比如谁在什么时间做了什么操作,等等. 把这些对于开发人员开说无关痛痒的代码写死在业务方法中实在不是一件很舒服的事情,于是AOP应运而生 ...