一、引言
今天我们开始讲“行为型”设计模式的第九个模式,该模式是【访问者模式】,英文名称是: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 voID Draw(); 8 外界注入具体访问者 9 Accept(ShapeVisitor visitor); 10 } 11 12 抽象访问者 Visitor 13 ShapeVisitor 14 15 Visit(Rectangle shape); 16 17 Visit(Circle shape); 18 19 Visit(line shape); 20 21 这里有一点要说:Visit方法的参数可以写成Shape吗?就是这样 Visit(Shape shape),当然可以,但是ShapeVisitor子类Visit方法就需要判断当前的Shape是什么类型,是Rectangle类型,是Circle类型,或者是line类型。 22 23 24 具体访问者 ConcreteVisitor 25 sealed CustomVisitor : ShapeVisitor 26 27 针对Rectangle对象 28 overrIDe Visit(Rectangle shape) 29 { 30 Console.Writeline("针对Rectangle新的 *** 作!"); 31 } 32 针对Circle对象 33 Visit(Circle shape) 34 35 Console.Writeline(针对Circle新的 *** 作! 36 37 针对line对象 38 Visit(line shape) 39 40 Console.Writeline(针对line新的 *** 作! 41 42 43 44 矩形----相当于“具体节点角色” ConcreteElement 45 Rectangle : Shape 46 47 Draw() 48 49 Console.Writeline(矩形我已经画好! 50 51 52 Accept(ShapeVisitor visitor) 53 54 visitor.Visit(this 55 56 57 58 圆形---相当于“具体节点角色”ConcreteElement 59 Circle : Shape 60 61 62 63 Console.Writeline(圆形我已经画好! 64 65 66 67 68 visitor.Visit( 69 70 71 72 直线---相当于“具体节点角色” ConcreteElement 73 line : Shape 74 75 76 77 Console.Writeline(直线我已经画好! 78 79 80 81 82 visitor.Visit( 83 84 85 86 结构对象角色 87 internal AppStructure 88 89 private ShapeVisitor _visitor; 90 91 public AppStructure(ShapeVisitor visitor) 92 93 this._visitor = visitor; 94 95 96 Process(Shape shape) 97 98 shape.Accept(_visitor); 99 100 101 102 Program103 104 static voID Main(string[] args)105 106 如果想执行新增加的 *** 作107 ShapeVisitor visitor = new CustomVisitor();108 AppStructure app = AppStructure(visitor);109 110 Shape shape = Rectangle();111 shape.Draw();执行自己的 *** 作112 app.Process(shape);执行新的 *** 作113 114 115 shape = Circle();116 shape.Draw();117 app.Process(shape);118 119 120 shape = line();121 shape.Draw();122 app.Process(shape);123 124 125 Console.Readline();126 127 128 }
这是访问者模式第二种代码实例:
Visitor抽象访问者角色 Visitor PutTelevision(Television tv); 7 PutComputer(Computer comp); 9 10 11 具体访问者角色 ConcreteVisitor SizeVisitor : Visitor 13 14 PutTelevision(Television tv) 15 16 Console.Writeline(按商品大小{0}排放,tv.Size); 17 PutComputer(Computer comp) 20 21 Console.Writeline( 23 24 26 StateVisitor : Visitor 27 按商品新旧值{0}排放 32 37 38 39 抽象节点角色 Element 40 Goods 42 Operate(Visitor visitor); 44 private int nSize; 45 Size 47 get { return nSize; } 48 set { nSize = value; } 49 50 51 nState; State 54 nState; } 55 set { nState = 57 58 具体节点角色 ConcreteElement 60 Television : Goods 61 62 Operate(Visitor visitor) 63 64 visitor.PutTelevision( 65 66 67 68 69 Computer : Goods 71 72 73 visitor.PutComputer( 75 76 77 78 StoragePlatform 79 private IList<Goods> List = new List<Goods>(); 81 82 Attach(Goods element) List.Add(element); 85 86 87 Detach(Goods element) 89 List.Remove(element); 90 91 92 93 94 foreach (Goods g in List) 95 { 96 g.Operate(visitor); }100 101 102 103 104 105 StoragePlatform platform = StoragePlatform();106 platform.Attach( Television());107 platform.Attach( Computer());108 109 SizeVisitor sizeVisitor = SizeVisitor();110 StateVisitor stateVisitor = StateVisitor();111 112 platform.Operate(sizeVisitor);113 platform.Operate(stateVisitor);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#来写设计模式了,写出来的代码会更棒。
以上是内存溢出为你收集整理的C#设计模式之二十一访问者模式(Visitor Pattern)【行为型】全部内容,希望文章能够帮你解决C#设计模式之二十一访问者模式(Visitor Pattern)【行为型】所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)