一、引言

今天我们开始讲“行为型”设计模式的第九个模式,该模式是【访问者模式】,英文名称是:Visitor Pattern。如果按老规矩,先从名称上来看看这个模式,我根本不能获得任何对理解该模式有用的信息,而且这个模式在我们的编码生活中使用的并不是很多。该模式的意图定义很抽象,第一次看了这个定义其实和没看没有什么区别,一头雾水,为了让大家更好的理解该模式的初衷,我们举个例子来说明模式。比如:当我们为了解决一个新的软件需求的时候,经过多个日以继夜的努力,最终通过一个完美(自己认为的)的软件设计解决了客户提出的新的需求,而且这个设计有完美的类层次结构,并且是符合OO的设计原则的,我们很开心,对自己设计的东西很有成就感。又过了一段时间,客户突然又有了一个新的需求,需要为现有的类层次结构里面的类增加一个新的操作(其实就是一个方法),怎么办?好办,在面向OO设计模式中有一个模式就是为了解决这个问题的,那就是“访问者模式”,可以为现有的类层次结构中的类轻松增加新的操作,我们继续吧,好好的了解一下该模式。

二、访问者模式的详细介绍

2.1、动机(Motivate)

在软件构建过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法),如果直接在基类中做这样的更改,将会给子类带来很繁重的变更负担,甚至破坏原有设计。如何在不更改类层次结构的前提下,在运行时根据需要透明地为类层次结构上的各个类动态添加新的操作,从而避免上述问题?

2.2、意图(Intent)

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

2.3、结构图(Structure)

2.4、模式的组成
    
    可以看出,在访问者模式的结构图有以下角色:

(1)、抽象访问者角色(Vistor): 声明一个包括多个访问操作,多个操作针对多个具体节点角色(可以说有多少个具体节点角色就有多少访问操作),使得所有具体访问者必须实现的接口。

(2)、具体访问者角色(ConcreteVistor):实现抽象访问者角色中所有声明的接口,也可以说是实现对每个具体节点角色的新的操作。

(3)、抽象节点角色(Element):声明一个接受操作,接受一个访问者对象作为参数,如果有其他参数,可以在这个“接受操作”里在定义相关的参数。

(4)、具体节点角色(ConcreteElement):实现抽象元素所规定的接受操作。

(5)、结构对象角色(ObjectStructure):节点的容器,可以包含多个不同类或接口的容器。

2.5、访问者模式的代码实现

访问者这个模式在我们现实的编码生活中使用的并不是很多,我就直接贴代码,让大家看代码的结构吧。今天给大家两个代码实例,自己慢慢体会访问者吧。实现代码如下:

  1 namespace Vistor
  2 {
  3     //抽象图形定义---相当于“抽象节点角色”Element
  4     public abstract class Shape
  5     {
  6         //画图形
  7         public abstract void Draw();
  8         //外界注入具体访问者
  9         public abstract void Accept(ShapeVisitor visitor);
 10     }
 11
 12     //抽象访问者 Visitor
 13     public abstract class ShapeVisitor
 14     {
 15         public abstract void Visit(Rectangle shape);
 16
 17         public abstract void Visit(Circle shape);
 18
 19         public abstract void Visit(Line shape);
 20
 21         //这里有一点要说:Visit方法的参数可以写成Shape吗?就是这样 Visit(Shape shape),当然可以,但是ShapeVisitor子类Visit方法就需要判断当前的Shape是什么类型,是Rectangle类型,是Circle类型,或者是Line类型。
 22     }
 23
 24     //具体访问者 ConcreteVisitor
 25     public sealed class CustomVisitor : ShapeVisitor
 26     {
 27         //针对Rectangle对象
 28         public override void Visit(Rectangle shape)
 29         {
 30             Console.WriteLine("针对Rectangle新的操作!");
 31         }
 32         //针对Circle对象
 33         public override void Visit(Circle shape)
 34         {
 35             Console.WriteLine("针对Circle新的操作!");
 36         }
 37         //针对Line对象
 38         public override void Visit(Line shape)
 39         {
 40             Console.WriteLine("针对Line新的操作!");
 41         }
 42     }
 43
 44     //矩形----相当于“具体节点角色” ConcreteElement
 45     public sealed class Rectangle : Shape
 46     {
 47         public override void Draw()
 48         {
 49             Console.WriteLine("矩形我已经画好!");
 50         }
 51
 52         public override void Accept(ShapeVisitor visitor)
 53         {
 54             visitor.Visit(this);
 55         }
 56     }
 57
 58     //圆形---相当于“具体节点角色”ConcreteElement
 59     public sealed class Circle : Shape
 60     {
 61         public override void Draw()
 62         {
 63             Console.WriteLine("圆形我已经画好!");
 64         }
 65
 66         public override void Accept(ShapeVisitor visitor)
 67         {
 68             visitor.Visit(this);
 69         }
 70     }
 71
 72     //直线---相当于“具体节点角色” ConcreteElement
 73     public sealed class Line : Shape
 74     {
 75         public override void Draw()
 76         {
 77             Console.WriteLine("直线我已经画好!");
 78         }
 79
 80         public override void Accept(ShapeVisitor visitor)
 81         {
 82             visitor.Visit(this);
 83         }
 84     }
 85
 86     //结构对象角色
 87     internal class AppStructure
 88     {
 89         private ShapeVisitor _visitor;
 90
 91         public AppStructure(ShapeVisitor visitor)
 92         {
 93             this._visitor = visitor;
 94         }
 95
 96         public void Process(Shape shape)
 97         {
 98             shape.Accept(_visitor);
 99         }
100     }
101
102     class Program
103     {
104         static void Main(string[] args)
105         {
106             //如果想执行新增加的操作
107             ShapeVisitor visitor = new CustomVisitor();
108             AppStructure app = new AppStructure(visitor);
109
110             Shape shape = new Rectangle();
111             shape.Draw();//执行自己的操作
112             app.Process(shape);//执行新的操作
113
114
115             shape = new Circle();
116             shape.Draw();//执行自己的操作
117             app.Process(shape);//执行新的操作
118
119
120             shape = new Line();
121             shape.Draw();//执行自己的操作
122             app.Process(shape);//执行新的操作
123
124
125             Console.ReadLine();
126         }
127     }
128 }

这是访问者模式第二种代码实例:

  1 namespace Visitor
  2 {
  3     //抽象访问者角色 Visitor
  4     public abstract class Visitor
  5     {
  6         public abstract void PutTelevision(Television tv);
  7
  8         public abstract void PutComputer(Computer comp);
  9     }
 10
 11     //具体访问者角色 ConcreteVisitor
 12     public sealed class SizeVisitor : Visitor
 13     {
 14         public override void PutTelevision(Television tv)
 15         {
 16             Console.WriteLine("按商品大小{0}排放", tv.Size);
 17         }
 18
 19         public override void PutComputer(Computer comp)
 20         {
 21             Console.WriteLine("按商品大小{0}排放", comp.Size);
 22         }
 23     }
 24
 25     //具体访问者角色 ConcreteVisitor
 26     public sealed class StateVisitor : Visitor
 27     {
 28         public override void PutTelevision(Television tv)
 29         {
 30             Console.WriteLine("按商品新旧值{0}排放", tv.State);
 31         }
 32
 33         public override void PutComputer(Computer comp)
 34         {
 35             Console.WriteLine("按商品新旧值{0}排放", comp.State);
 36         }
 37     }
 38
 39     //抽象节点角色 Element
 40     public abstract class Goods
 41     {
 42         public abstract void Operate(Visitor visitor);
 43
 44         private int nSize;
 45         public int Size
 46         {
 47             get { return nSize; }
 48             set { nSize = value; }
 49         }
 50
 51         private int nState;
 52         public int State
 53         {
 54             get { return nState; }
 55             set { nState = value; }
 56         }
 57     }
 58
 59     //具体节点角色 ConcreteElement
 60     public sealed class Television : Goods
 61     {
 62         public override void Operate(Visitor visitor)
 63         {
 64             visitor.PutTelevision(this);
 65         }
 66     }
 67
 68     //具体节点角色 ConcreteElement
 69     public sealed class Computer : Goods
 70     {
 71         public override void Operate(Visitor visitor)
 72         {
 73             visitor.PutComputer(this);
 74         }
 75     }
 76
 77     //结构对象角色
 78     public sealed class StoragePlatform
 79     {
 80         private IList<Goods> list = new List<Goods>();
 81
 82         public void Attach(Goods element)
 83         {
 84             list.Add(element);
 85         }
 86
 87         public void Detach(Goods element)
 88         {
 89             list.Remove(element);
 90         }
 91
 92         public void Operate(Visitor visitor)
 93         {
 94             foreach (Goods g in list)
 95             {
 96                 g.Operate(visitor);
 97             }
 98         }
 99     }
100
101     class Program
102     {
103         static void Main(string[] args)
104         {
105             StoragePlatform platform = new StoragePlatform();
106             platform.Attach(new Television());
107             platform.Attach(new Computer());
108
109             SizeVisitor sizeVisitor = new SizeVisitor();
110             StateVisitor stateVisitor = new StateVisitor();
111
112             platform.Operate(sizeVisitor);
113             platform.Operate(stateVisitor);
114
115             Console.Read();
116         }
117     }
118 }

三、访问者模式的实现要点:

Visitor模式通过所谓双重分发(double dispatch)来实现在不更改Element类层次结构的前提下,在运行时透明地为类层次结构上的各个类动态添加新的操作。所谓双重分发即Visitor模式中间包括了两个多态分发(注意其中的多态机制):第一个为accept方法的多态辨析;第二个为visit方法的多态辨析。

  设计模式其实是一种堵漏洞的方式,但是没有一种设计模式能够堵完所有的漏洞,即使是组合各种设计模式也是一样。每个设计模式都有漏洞,都有它们解决不了的情况或者变化。每一种设计模式都假定了某种变化,也假定了某种不变化。Visitor模式假定的就是操作变化,而Element类层次结构稳定。

(1)、访问者模式的主要优点有:

1】、访问者模式使得添加新的操作变得容易。如果一些操作依赖于一个复杂的结构对象的话,那么一般而言,添加新的操作会变得很复杂。而使用访问者模式,增加新的操作就意味着添加一个新的访问者类。因此,使得添加新的操作变得容易。

2】、访问者模式使得有关的行为操作集中到一个访问者对象中,而不是分散到一个个的元素类中。这点类似与”中介者模式”。

3】、访问者模式可以访问属于不同的等级结构的成员对象,而迭代只能访问属于同一个等级结构的成员对象。

 (2)、访问者模式的主要缺点有:

1】、增加新的元素类变得困难。每增加一个新的元素意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中添加相应的具体操作。具体来说,Visitor模式的最大缺点在于扩展类层次结构(增添新的Element子类),会导致Visitor类的改变。因此Visitor模式适用于“Element类层次结构稳定,而其中的操作却经常面临频繁改动”。

(3)、在下面的情况下可以考虑使用访问者模式:

1】、如果系统有比较稳定的数据结构,而又有易于变化的算法时,此时可以考虑使用访问者模式。因为访问者模式使得算法操作的添加比较容易。

2】、如果一组类中,存在着相似的操作,为了避免出现大量重复的代码,可以考虑把重复的操作封装到访问者中。(当然也可以考虑使用抽象类了)

3】、如果一个对象存在着一些与本身对象不相干,或关系比较弱的操作时,为了避免操作污染这个对象,则可以考虑把这些操作封装到访问者对象中。

四、.NET 访问者模式的实现

在现在的Net框架里面,如果要想给现有的类增加新的方法,有了新的方式,那就是“扩展方法”,使用起来和实例方法是一样一样的,而且在Net框架里面,微软自己也写了很多的扩展方法给我们使用。我目前还没有学习到Net的框架类库里面有“访问者模式”实现,看来自己还需努力,革命尚未成功啊。

五、总结

访问者模式写完了,这个模式刚开始理解起来还是挺麻烦的,但是,如果我们多看几个实例代码,完全掌握也不是问题。随着C#语言的发展,设计模式里面的很多东西,我们可以通过C#语言的一些特性做更好的替代。我们写设计模式刚开始要慢慢来,一步一步的照猫画虎的来写代码,等我们熟练掌握了模式的核心意思,我们就要写符合C#风格和特性的模式代码了,或者说我们要用C#来写设计模式了,写出来的代码会更棒。

转载于:https://www.cnblogs.com/PatrickLiu/p/8135083.html

C#设计模式之二十一访问者模式(Visitor Pattern)【行为型】相关推荐

  1. 二十四种设计模式:访问者模式(Visitor Pattern)

    访问者模式(Visitor Pattern) 介绍 表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作. 示例 有一个Message实体类,某些对 ...

  2. 大话设计模式十二:访问者模式

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

  3. 设计模式:访问者模式(Visitor Pattern)

    访问者模式(Visitor Pattern): 封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作. 主要将数据结构与数据操作分离,解决数据结构和操作 ...

  4. [设计模式] 23 访问者模式 visitor Pattern

    在GOF的<设计模式:可复用面向对象软件的基础>一书中对访问者模式是这样说的:表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作.访问 ...

  5. 设计模式(二) 访问者模式 Vistor

    在软件开发中,经常需要用到多态,继承等机制,下面是很常见的一段代码 class Brand { public:virtual void productShoe() = 0; }class Nike : ...

  6. 40访问者模式(Visitor Pattern)

    类层次结构的变化:     类层次结构中可能经常由于引入新的操作,从而将类型变得脆弱...                             动机:     在软件构建过程中,由于需求的改变,某 ...

  7. java的visitor模式_java设计模式(二十一)访问者模式(Visitor)

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

  8. 设计模式的征途—16.访问者(Visitor)模式

    在患者就医时,医生会根据病情开具处方单,很多医院都会存在以下这个流程:划价人员拿到处方单之后根据药品名称和数量计算总价,而药房工作人员根据药品名称和数量准备药品,如下图所示. 在软件开发中,有时候也需 ...

  9. 中介者模式 调停者 Mediator 行为型 设计模式(二十一)

    中介者模式(Mediator) 调度.调停 意图 用一个中介对象(中介者)来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散 而且可以独立地改变它们之间的交互. 中介者模式又 ...

最新文章

  1. k8s之informer简单理解
  2. 【坐在马桶上看算法】算法4:队列——解密QQ号
  3. python集合的两种类型_python 入门之 – 集合类型(十九)
  4. 【bzoj5037】[Jsoi2014]电信网络 最大权闭合图
  5. Linux Ubuntu 内核升级
  6. moment获取几小时前_请问怎么把“多少小时前”精确到“多少小时多少分钟前”...
  7. Kotlin — 适用于 Web 开发
  8. Prototype使用$$()函数
  9. mysql如何让自增id从1开始设置方法
  10. poj 3190(贪心)
  11. Linux串口分析open
  12. 使用rsync实现客户端与服务器端的文件同步与传送
  13. word论文页码从任意页开始编号
  14. HTMl载入FLV格式网页视频播放器
  15. 爱奇艺面向海量设备的边缘计算PAAS平台及应用实践
  16. C语言实现三子棋游戏(规范化)
  17. 挑选代表( 招商银行信用卡中心)
  18. Ignite Beijing 2019你参加了吗?多图,慎点!
  19. Python类和对象使用
  20. MATLAB一直显示初始化的解决方法

热门文章

  1. 连接mysql超过连接次数处理办法
  2. 一个双线程下同一时候操作指针变量导致野指针出现的问题总结
  3. 话说模式匹配(1) 什么是模式?
  4. IplImage 封装释放
  5. 拇指接龙游戏从WIN32向Xcode 4.5移植过程问题记录
  6. 刚刚修复的Windows 0day和Chrome 0day 已被组合用于 WizardOpium 攻击(详解)
  7. JAVA8给我带了什么——并流行和接口新功能
  8. 初创企业如何实现2天快速上线?
  9. centos7改语言包
  10. SQL Management Studio Express 安装缺少MSXML6解决