访问者模式 - 行为模式

个人理解:    

模式类型:

    Visitor  访问者模式 - 行为模式
    
意图:
    Represents an operation to be performed on the elements of an object structure.
    Visitor lets you define a new operation without changing the classes of the elements on which it operates.
    访问者模式是对象的行为模式。访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变。

    
概述:
    访问者模式适用于数据结构相对未定的系统,它把数据结构和作用于结构之上的操作之间的耦合解脱开,使得操作集合可以相对自由的演化。
     数据结构的每一个节点都可以接受一个访问者的调用,此节点向访问者对象传入节点对象,二访问者对象则反过来执行节点对象的操作。这样的过程叫做“双重分派”。节点调用访问者,将它自己传入,访问者则将某算法针对此节点执行。
     双重分派意味着施加于节点之上的操作是基于访问者和节点本身的数据类型,而不仅是其中的一者。
    
角色:
    抽象访问者(Visitor)角色:声明了一个或者多个方法操作,形成所有的具体访问者角色必须实现的接口。
    具体访问者(ConcreteVisitor)角色:实现抽象访问者所声明的接口,也就是抽象访问者所声明的各个访问操作。
    抽象节点(Node)角色:声明一个接受操作,接受一个访问者对象作为一个参数。
    具体节点(ConcreteNode)角色:实现了抽象节点所规定的接受操作。
    结构对象(ObjectStructure)角色:有如下的责任,可以遍历结构中的所有元素;如果需要,提供一个高层次的接口让访问者对象可以访问每一个元素;如果需要,可以设计成一个复合对象或者一个聚集,如List或Set。

结构图:


模式的应用场景:

The visitor pattern is used when:
    Similar operations have to be performed on objects of different types grouped in a structure (a collection or a more complex structure).
    There are many distinct and unrelated operations needed to be performed. Visitor pattern allows us to create a separate visitor concrete class for each type of operation and to separate this operation implementation from the objects structure.
    The object structure is not likely to be changed but is very probable to have new operations which have to be added. Since the pattern separates the visitor (representing operations, algorithms, behaviors) from the object structure it is very easy to add new visitors as long as the structure remains unchanged.
        --------------------
    在很多情况下不使用设计模式反而会得到一个比较好的设计。每一个设计模式都有其不应当使用的地方。访问者模式也有不应当使用的情况。
    1、倾斜的扩展性
     访问者模式仅当在被访问的类结构非常稳定的情况下使用。换言之,系统很少出现需要加入新节点的情况。如果出现需要加入新节点的情况怎么办呢?那时就必须在每个访问对象里加入一个对应于这个新节点的访问操作,而这是对系统的大规模修改,因而是违背“开-闭”原则的。
     访问者模式允许在节点中加入新的方法,相应的仅仅需要在一个新的访问者类加入此方法,而不需要在每一个访问者类中都加入此方法。
     显然,访问者模式提供了倾斜的可扩展设计:方法集合的可扩展性和类集合的不可扩展性。
     换言之,如果系统的数据结构是频繁变化的,则不适合使用访问者模式。
    2、“开—闭”原则和对变化的封装
     面向对象的设计原则只最重要的便是所谓的“开—闭”原则。一个软件系统的设计应当尽量做到对扩展开放,对修改关闭。达到这个原则的途径就是遵循“对变化的封装”的原则。即在进行软件系统的设计时,应当设法找出一个软件系统中会变化的部分,将之封装起来。
     很多的系统可以按照算法和数据结构分开,也就是说一些对象含有算法,而另一些对象含有数据,接受算法的操作。如果这样的系统有比较稳定的数据结构,又有易于变化的算法的话,使用访问者没收就是比较合适的。因为访问者没收使得算法操作的增加变得容易。
     反过来,如果一个系统的数据结构对象易于变化,经常要有新的数据对象增加进来的话,就不适合使用访问者没收。因为在访问者没收中增加新的节点很困难,要涉及到在抽象访问者和所有的具体访问者中增加新的方法。


模式的优缺点:

优点
     (1)访问者模式使得增加新的操作变得很容易。如果一些操作依赖于一个复杂得结构对象的话,那么一般而言,增加新的操作会很复杂。而使用访问者模式,增加新的操作就意味着增加一个新的访问者类,因此,变的很容易。
     (2)访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个节点类中。
     (3)访问者模式可以跨越几个类得等级结构访问属于不同的等级结构的成员类。迭代子只能访问属于同一个类型等级结构的成员对象,而不能访问属于不同等级结构的对象。访问者模式可以做到这一点。
缺点
     (1)增加新的节点变的很困难。每增加一个新的节点都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作。
     (2)破坏封装。访问者模式要求访问者对象访问者并调用每一个节点对象的操作,这隐含了一个对所有节点对象的要求:它们必须暴露一些自己的操作和内部状态。不然,访问者的访问者就变得没有意义。由于访问者对象自己会积累访问者操作所需的状态,从而使这些状态不再存储在节点对象中,这也是破坏封装的。
    

代码(其实读UML图要比代码还要一目了然):

package com.lee.desingerPattener23.visitor;

import java.util.Enumeration;
import java.util.Vector;

public class Client {
	private static ObjectStructure aObjects;
	private static Visitor visitor;

	static public void main(String[] args) {
		// 创建一个结构对象
		aObjects = new ObjectStructure();
		// 给结构增加一个节点
		aObjects.add(new NodeA());
		aObjects.add(new NodeB());
		// 创建一个新的访问者
		visitor = new VisitorA();
		// 让访问者访问节点
		aObjects.action(visitor);
	}
}

interface Visitor {
	// 访问节点A的操作
	void visit(NodeA node);
	// 访问节点B的操作
	void visit(NodeB node);
}

class VisitorA implements Visitor {
	public void visit(NodeA nodeA) {
		System.out.println(nodeA.operationA());
	}
	public void visit(NodeB nodeB) {
		System.out.println(nodeB.operationB());
	}
}

class VisitorB implements Visitor {
	public void visit(NodeA nodeA) {
		System.out.println(nodeA.operationA());
	}
	public void visit(NodeB nodeB) {
		System.out.println(nodeB.operationB());
	}
}

abstract class Node {
	public abstract void accept(Visitor visitor);
}

class NodeA extends Node {
	public void accept(Visitor visitor) {
		visitor.visit(this);
	}

	public String operationA() {
		return "NodeA is visited";
	}
}

class NodeB extends Node {
	public void accept(Visitor visitor) {
		visitor.visit(this);
	}

	public String operationB() {
		return "NodeB is visited";
	}
}

class ObjectStructure {
	private Vector nodes;
	private Node node;

	// 构造方法
	public ObjectStructure() {
		nodes = new Vector();
	}
	// 执行访问操作
	public void action(Visitor visitor) {
		for (Enumeration e = nodes.elements(); e.hasMoreElements();) {
			node = (Node) e.nextElement();
			node.accept(visitor);
		}
	}
	// 增加一个新元素
	public void add(Node node) {
		nodes.addElement(node);
	}
}

结果:

NodeA is visited
NodeB is visited

为什么不是

a.operationA();
NodeB b = new NodeB(); 
a.operationB();

这样的结果是一样的。

因为以后可能还会再加上

NodeC c = new NodeC();
c.operationC();
所以,现在加上Node (接受一个访问者对象作为一个参数),然后通过Visitor去访问,而ObjectStructure则是存储所有的元素。


所有模式:
     创建型模式,共五种:工厂方法模式、抽象工厂模式单例模式建造者模式原型模式
结构型模式,共七种:适配器模式装饰器模式代理模式外观模式桥接模式组合模式享元模式
    行为型模式,共十一种:策略模式模板方法模式观察者模式迭代子模式责任链模式命令模式备忘录模式状态模式访问者模式中介者模式解释器模式

    补充模式:空对象模式


参考/转自:
http://www.oodesign.com/visitor-pattern.html
http://www.tutorialspoint.com/design_pattern/visitor_pattern.htm
http://www.cnblogs.com/java-my-life/archive/2012/06/14/2545381.html

转载请注明:   http://blog.csdn.net/paincupid/article/details/46988559

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值