访问者模式(Visitor Pattern)

目的:

在不改变一个已存在的类的层次结构的情况下,为这个层次结构中的某些类定义一个新的操作,这个新的操作作用于(操作)已存在的类对象,也即新的操作需要访问被作用的对象。

应用范围:

一个对象层次结构中包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。例如访问类一般访问的是类层次中最低层的类(具体类,其父类假设为抽象类)对象。

需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作污染这些对象的类。Visitor使得你可以将相关的操作集中起来定义在一个类中。当该对象结构被很多应用(访问类)共享时,用Visitor模式让每个应用(访问类)仅包含需要用到的操作。

定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。

 

简单形式:

访问者模式需要被扩展的类层次结构提供必要的支持。

访问者模式的机制包括:

1 在一个层次结构中,为某些类或者所有类都增加一个Accept()操作。这个方法的每个实现都可以接收一个参数。参数的类型是我们将要创建的一个接口。

2 利用一些操作创建一个接口。这些操作可以共享一个公共名称(如Visitor),但是具有不同的参数类型。在需要进行扩展的层次结构中。每个类都要声明一个这样的操作。

访问者模式(Visitor Pattern)_第1张图片

如以上的类图所示,每一个被访问的Element类,都必须带有一个Accept()方法,以能接受访问者IVisitor接口的访问;而每一个访问者的实现类CarryElementVisitorDeleteElementVisitor类分别实现了对Element类的子类Element1Element2Carry(运送)Delete(删除)操作。

以下的序列图演示了删除一个Element1对象的过程。

访问者模式(Visitor Pattern)_第2张图片

如序列图所示,模式的使用者先分别创建了一个DeleteElementVisitor的访问者visitor对象和一个Element1的被访问者element对象,然后使用者向element发送Accept()消息,以让element接受visitor的访问,而element又进一步向访问者visitor发送Visitor()消息,以让访问者访问自己,以达到使用者删除element对象的目的。这也是所谓的二次分发的过程。二次分发的好处在带有聚合关系的形式中才能得以体现。

由此可见每一个Visitor子类其实是实现一个扩展的新的行为。而当将这个子类传入被访问对象时,实际是对被访问对象执行了所实现的新的行为。

 

聚合形式:

在类层次中添加一个集合对象(或由集合对象组成的对象),可以解决有聚合关系的场合的应用,对集合中的所有对象执行相同的操作。添加集合对象的类图如下,其中的Collection对象就是人们常说的ObjectStructure对象。

访问者模式(Visitor Pattern)_第3张图片

而相对于集合对象的Delete操作可以用下面的序列图表示:

访问者模式(Visitor Pattern)_第4张图片

如上图所示,使用者向Collection对象发送Accept()消息,而Collection对象再向集合中的每一个Element(不是Element1Element2)对象发送Accept()消息以完成访问操作。

这时,二次分发的好处也开始出现:VisitorClient对象并不需要知道其最后具体调用的是哪个Visitor()方法,对于Collection中的每一个Element,而是利用Element子类的继承多态和IVisitor接口重载的Visitor()方法,交由编译器去确定。

 

 

混合(合成模式)形式:

将简单形式和集合形式的二种情况合在一起,则得到第三种形式,如下图所示。


从上图可以看出,在这种混合的形式下,ElementCollection即是Element的一个子类,同时又是由Element组合成的一个对象,这就类似于控件也可以是其他控件的容器这种情况。此时,会出现一个问题,这是一种默认可以产生环形结构的一种形式,如果在不加限制的情况下生成一些对象后再使用递归,将出现死循环,所以在使用的过程中必须设法进行限制。这也说明了,在使用Visitor模式的时候,要求访问者必须对被访问者的结构有所了解。

同时,IComplexVisitor与前面的IVisitor接口的Visitor()方法所接受的参数也发生了变化,这是由于被访问者的类层次发生了变化,这也要求Visitor模式将被常用于被访问者的类层次相当稳定的情况下,否则一旦被访问者发生变化,所必须进行的修改也将是巨大的。比如在数据结构(被访问者)和算法(访问者)分离使用Visitor模式的情况下,数据结构必须是相当稳定,数据结构一旦变化,所有相关的算法也必须进行修改而与之相适应。

 

 

访问者模式的优点:

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

访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中。

 

访问者模式的缺点:

如果被访问者的类层次是多变的,访问者模式将不适用。

访问者在需要进行某些操作时,必须要能得到被访问者的一些内部数据,这也限制了访问者的所有支持的功能。

你可能感兴趣的:(Design,Patterns,数据结构,delete,扩展,算法,编译器)