`
zzq19860626
  • 浏览: 261023 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
博客专栏
B20df9e2-fb3d-3644-9f72-c1619842f682
设计模式学习笔记
浏览量:177991
87eaf24f-812a-3463-8e65-e3197d2ad8c2
java虚拟机
浏览量:26192
社区版块
存档分类
最新评论

JAVA设计模式学习24——访问者模式

阅读更多

访问者(Visitor)模式:封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。访问者模式的结构如下:


 通过上图可以看到他有如下角色:

抽象访问者(Visitor)角色:定义接口,声明一个或多个访问操作。 
具体访问者(ConcreteVisitor)角色:实现抽象访问者所声明的接口,也就是抽象访问者所声明的各个访问操作。 
抽象元素(Visitable)角色:声明一个接受操作,接受一个访问者对象作为一个参数。 
具体元素结点(ConcreteElement)角色:实现抽象结点所规定的接受操作。 
数据结构对象(ObjectStructure)角色:可以遍历结构中的所有元素,提供一个接口让访问者对象都可以访问每一个元素。 
模拟代码如下:
package visitor;
/**
 * 
 *作者:alaric
 *时间:2013-9-13下午11:31:28
 *描述:抽象访问者
 */
public interface Visitor {

	public void visit(ConcreteElementB able );
	public void visit(ConcreteElementA able );
}
 
package visitor;
/**
 * 
 *作者:alaric
 *时间:2013-9-13下午11:31:46
 *描述:抽象角色元素
 */
public interface Visitable {
	
	public void accept(Visitor v);

}
 
package visitor;
/**
 * 
 *作者:alaric
 *时间:2013-9-13下午11:33:29
 *描述:具体访问者A
 */
public class ConcreteVisitorA implements Visitor{

	@Override
	public void visit(ConcreteElementB able) {
		able.operate();
	}

	@Override
	public void visit(ConcreteElementA able) {
		// TODO Auto-generated method stub
		able.operate();
	}
	

}
 
package visitor;

/**
 * 
 *作者:alaric
 *时间:2013-9-13下午11:32:55
 *描述:具体访问者B
 */
public class ConcreteVisitorB implements Visitor{

	@Override
	public void visit(ConcreteElementB able) {
		able.operate();
	}

	@Override
	public void visit(ConcreteElementA able) {
		// TODO Auto-generated method stub
		able.operate();
	}

	

}
 
package visitor;
/**
 * 
 *作者:alaric
 *时间:2013-9-13下午11:34:02
 *描述:具体元素A
 */
public class ConcreteElementA implements Visitable {

	@Override
	public void accept(Visitor v) {
		v.visit(this);
	}

	public void operate(){
		System.out.println("ConcreteElementA ....");
	}
}
 
package visitor;
/**
 * 
 *作者:alaric
 *时间:2013-9-13下午11:33:40
 *描述:具体元素B
 */
public class ConcreteElementB implements Visitable {

	@Override
	public void accept(Visitor v) {
		v.visit(this);
	}

	public void operate(){
		System.out.println("ConcreteElementB ....");
	}
}
 
package visitor;

import java.util.ArrayList;
import java.util.List;
/**
 * 
 *作者:alaric
 *时间:2013-9-13下午11:34:22
 *描述:客户端
 */
public class Client {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		Visitor v1 = new ConcreteVisitorA();
		List<Visitable> list = new ArrayList<>();
		list.add(new ConcreteElementA());
		list.add(new ConcreteElementB());
		
		for(Visitable able :list){
			able.accept(v1);
		}
	
	}

}
 

看了很多设计模式的书,讲访问者设计模式都要提到一个概念“双重分派”,所谓“分派”简单理解就是根据类的特性,特征进行选择,这些选择都是程序语言设计的特征,比如多态(重载,重写)等等,我个人不太注重概念,只要深入掌握面向对象的基础就很好理解了。

 

设计模式相对其他模式来说结构有点复杂,上面是访问者模式的模拟实现,为了利于学习找了个真实的例子。dom4j里面利用访问者模式来对xml文档进行逐个节点访问,所有文档的对象的父类接口都是Node,对于不同类型的文档对象又做了不同的抽象,所有可能访问的节点如Visitor类中所示,dom4j中定义的Visitor接口如下:

/*
 * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
 *
 * This software is open source.
 * See the bottom of this file for the licence.
 */

package org.dom4j;

/**
 * <p>
 * <code>Visitor</code> is used to implement the <code>Visitor</code>
 * pattern in DOM4J. An object of this interface can be passed to a
 * <code>Node</code> which will then call its typesafe methods. Please refer
 * to the <i>Gang of Four </i> book of Design Patterns for more details on the
 * <code>Visitor</code> pattern.
 * </p>
 * 
 * <p>
 * This <a href="http://www.patterndepot.com/put/8/JavaPatterns.htm">site </a>
 * has further discussion on design patterns and links to the GOF book. This <a
 * href="http://www.patterndepot.com/put/8/visitor.pdf">link </a> describes the
 * Visitor pattern in detail.
 * </p>
 * 
 * @author <a href="mailto:james.strachan@metastuff.com">James Strachan </a>
 * @version $Revision: 1.8 $
 */
public interface Visitor {
    /**
     * <p>
     * Visits the given <code>Document</code>
     * </p>
     * 
     * @param document
     *            is the <code>Document</code> node to visit.
     */
    void visit(Document document);

    /**
     * <p>
     * Visits the given <code>DocumentType</code>
     * </p>
     * 
     * @param documentType
     *            is the <code>DocumentType</code> node to visit.
     */
    void visit(DocumentType documentType);

    /**
     * <p>
     * Visits the given <code>Element</code>
     * </p>
     * 
     * @param node
     *            is the <code>Element</code> node to visit.
     */
    void visit(Element node);

    /**
     * <p>
     * Visits the given <code>Attribute</code>
     * </p>
     * 
     * @param node
     *            is the <code>Attribute</code> node to visit.
     */
    void visit(Attribute node);

    /**
     * <p>
     * Visits the given <code>CDATA</code>
     * </p>
     * 
     * @param node
     *            is the <code>CDATA</code> node to visit.
     */
    void visit(CDATA node);

    /**
     * <p>
     * Visits the given <code>Comment</code>
     * </p>
     * 
     * @param node
     *            is the <code>Comment</code> node to visit.
     */
    void visit(Comment node);

    /**
     * <p>
     * Visits the given <code>Entity</code>
     * </p>
     * 
     * @param node
     *            is the <code>Entity</code> node to visit.
     */
    void visit(Entity node);

    /**
     * <p>
     * Visits the given <code>Namespace</code>
     * </p>
     * 
     * @param namespace
     *            is the <code>Namespace</code> node to visit.
     */
    void visit(Namespace namespace);

    /**
     * <p>
     * Visits the given <code>ProcessingInstruction</code>
     * </p>
     * 
     * @param node
     *            is the <code>ProcessingInstruction</code> node to visit.
     */
    void visit(ProcessingInstruction node);

    /**
     * <p>
     * Visits the given <code>Text</code>
     * </p>
     * 
     * @param node
     *            is the <code>Text</code> node to visit.
     */
    void visit(Text node);
}

/*
 * Redistribution and use of this software and associated documentation
 * ("Software"), with or without modification, are permitted provided that the
 * following conditions are met:
 * 
 * 1. Redistributions of source code must retain copyright statements and
 * notices. Redistributions must also contain a copy of this document.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * 
 * 3. The name "DOM4J" must not be used to endorse or promote products derived
 * from this Software without prior written permission of MetaStuff, Ltd. For
 * written permission, please contact dom4j-info@metastuff.com.
 * 
 * 4. Products derived from this Software may not be called "DOM4J" nor may
 * "DOM4J" appear in their names without prior written permission of MetaStuff,
 * Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
 * 
 * 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
 * 
 * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
 */
 dom4j里面有个缺省的访问者(Visitor)的实现VisitorSupport,我们解析一个文档只需继承这个类,然后重写visit方法即可。一个简单的类图表示dom4j是怎么利用visitor设计模式的,如下图:
上图中Node的继承接口和实现类 还有很多这里就只标示了CharacterData及其他的子类。我只需要写XXX_Visitor就可以了。接下来我们写个例子看看:
我们要解析的XML如下:
<?xml version="1.0" encoding="UTF-8"?>
<table name="test">
  <rows>
      <row>
	    <id>1</id>
		<test>Test</test>
	  </row>
      <row>
	    <id>2</id>
		<test>Test2</test>
	  </row> 
 </rows
</table>
 我们写个客户端测试,为了简单,把Visitor作为内部类,直接就一个类完成,代码如下:  
package com.alaric.dom4j;

import java.io.File;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.VisitorSupport;
import org.dom4j.io.SAXReader;

public class Dom4jTest {


    public class MyVisitor extends VisitorSupport {

        public void visit(Attribute node){
          System.out.println("属性 : "+node.getName()+" = "+node.getValue());
        }

        public void visit(Element node){
          if(node.isTextOnly()){
            System.out.println("节点: "+node.getName()+" = "+node.getText());
          }else{
            System.out.println("节点:"+node.getName());
          }
        }
    }


    public static void main(String[] args) throws Exception {

        SAXReader saxReader=new SAXReader();
        File file=new File("d:\\test.xml");
        try{
          Document doc=saxReader.read(file);
          doc.accept(new Dom4jTest(). new MyVisitor());
        }catch(DocumentException de){
          de.printStackTrace();
        }

    }

}
 

运行结果:

节点:table

属性 : name = test

节点:rows

节点:row

节点: id = 1

节点: test = Test

节点:row

节点: id = 2

节点: test = Test2

 

可以看出把xml节点顺序的访问了一边。每个人可以根据不同的xml来实现自己的Visitor,不论怎么写都可以遍历出你所有的节点,这就是visitor的厉害之处。访问者模式也不是万能的,他的缺点是当数据结构变化时,他的visitor接口及其实现都要改变。所以访问者模式不能使用在经常变化的数据接口上。在Gof的设计模式中,有以下情形可以考虑使用设计模式:

 

1、一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
2、需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。Visitor使得你可以将相关的操作集中起来定义在一个类中。
3、当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作。
4、 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。

这些个人看来都是建议,项目中还要具体问题具体分析了。

 

设计模式系列目录:

  • 大小: 21.6 KB
  • 大小: 86.1 KB
3
5
分享到:
评论
4 楼 hialaric 2013-11-04  
hialaric 写道
dom4j这里例子我看过,的确用的不错

开始我只是模拟visitor,觉得用处不大,知道看了那个dom4j的源码,才知道原来如此强大。
3 楼 hialaric 2013-11-04  
pjwqq 写道
楼主第一个举例少了 ConcreteStructure,将它并入Client中了,感觉应该独立出来

你看的很认真啊,确实应该独立出来。
2 楼 pjwqq 2013-10-16  
楼主第一个举例少了 ConcreteStructure,将它并入Client中了,感觉应该独立出来
1 楼 hialaric 2013-09-16  
dom4j这里例子我看过,的确用的不错

相关推荐

    Java设计模式 版本2

    Java设计模式,目录:前言,UML建模技术,深入浅出UML类图,从招式与内功谈起——设计模式概述,面向对象设计原则,工厂三兄弟之简单工厂模式,工厂三兄弟之工厂方法模式,工厂三兄弟之抽象工厂模式,确保对象的唯一...

    java设计模式

    目录: 前 言 第一部分 大旗不挥,谁敢冲锋——热身篇 第1章 单一职责原则 1.1 我是“牛”类,我可以担任多职吗 1.2 绝杀技,打破你的传统思维 1.3 我单纯,所以我快乐 1.4 最佳实践 ...附录:23个设计模式

    《Java开发实战经典》——学习攻略

    并可以灵活的运用这些概念进行程序的分析,可以说在整个JAVA SE部分核心就是面向对象的开发,里面涉及的概念较多,但是所有的概念最终都是为接口和抽象类服务的,而所有JAVA开发中涉及到的各个设计模式,实际上也是...

    java多线程设计模式详解(PDF及源码)

    通过程序范例和UML图示来一一解说,书中代码的重要部分加了标注以使读者更加容易理解,再加上图文并茂,对于初学者还是程序设计高手来说,这都是一本学习和认识JAVA设计模式的一本好书。(注意,本资源附带书中源...

    深入浅出设计模式(中文版电子版)

    5.11VisitorPattern(访问者模式) 280 5.11.1定义 280 5.11.2现实例子——收银员收银计费 282 5.11.3C#实例——人事评估 283 5.11.4Java实例——维修工程师检查车辆 287 5.11.5优势和缺陷 291 5.11.6应用情??...

    java和设计模式ppt教程

    java和设计模式ppt包含工厂模式、建造模式、原始模型模式、单例模式、结构模式、适配器、桥梁模式、合成模式、装饰模式、门面模式、享元模式、代理模式、行为模式、解释器模式、迭代子模式、调停者模式、备忘录模式...

    design-pattern-java.pdf

    设计模式趣味学习(复习) 设计模式趣味学习(复习) 设计模式与足球(一) 设计模式与足球(二) 设计模式与足球(三) 设计模式与足球(四) 设计模式综合应用实例 设计模式综合应用实例 多人联机射击游戏 多人...

    深入浅出设计模式(中文版)

    5.11VisitorPattern(访问者模式) 280 5.11.1定义 280 5.11.2现实例子——收银员收银计费 282 5.11.3C#实例——人事评估 283 5.11.4Java实例——维修工程师检查车辆 287 5.11.5优势和缺陷 291 5.11.6应用情??...

    java高手真经 (UML建模+设计模式+面向服务架构) 卷6

    综合实例——Bug管理系统 (3)设计模式样例(24个讲解样例程序) pattern/src/principle/liskovsubstitution//10.3.2里氏代换原则 pattern/src/creation/factorymethod //11.1工厂方法模式 pattern/src/creation/...

    java高手真经 (UML建模+设计模式+面向服务架构) 卷8

    综合实例——Bug管理系统 (3)设计模式样例(24个讲解样例程序) pattern/src/principle/liskovsubstitution//10.3.2里氏代换原则 pattern/src/creation/factorymethod //11.1工厂方法模式 pattern/src/creation/...

    java高手真经 (UML建模+设计模式+面向服务架构) 卷3

    (3)设计模式样例(24个讲解样例程序) pattern/src/principle/liskovsubstitution//10.3.2里氏代换原则 pattern/src/creation/factorymethod //11.1工厂方法模式 pattern/src/creation/abstractfactory //11.2抽象...

    java高手真经 (UML建模+设计模式+面向服务架构) 卷1

    (3)设计模式样例(24个讲解样例程序) pattern/src/principle/liskovsubstitution//10.3.2里氏代换原则 pattern/src/creation/factorymethod //11.1工厂方法模式 pattern/src/creation/abstractfactory //11.2抽象...

    java高手真经 (UML建模+设计模式+面向服务架构) 卷9

    综合实例——Bug管理系统 (3)设计模式样例(24个讲解样例程序) pattern/src/principle/liskovsubstitution//10.3.2里氏代换原则 pattern/src/creation/factorymethod //11.1工厂方法模式 pattern/src/creation/...

    【白雪红叶】JAVA学习技术栈梳理思维导图.xmind

    访问者模式 设计案例 UML 架构 系统架构能力 基本理论 扩展性设计 可用性设计 可靠性设计 一致性设计 负载均衡设计 过载保护设计 协议设计 二进制协议 文本协议 接入层架构设计 DNS轮询 动静态...

    java高手真经 (UML建模+设计模式+面向服务架构) 卷10

    综合实例——Bug管理系统 (3)设计模式样例(24个讲解样例程序) pattern/src/principle/liskovsubstitution//10.3.2里氏代换原则 pattern/src/creation/factorymethod //11.1工厂方法模式 pattern/src/creation/...

    java高手真经 (UML建模+设计模式+面向服务架构) 卷5

    综合实例——Bug管理系统 (3)设计模式样例(24个讲解样例程序) pattern/src/principle/liskovsubstitution//10.3.2里氏代换原则 pattern/src/creation/factorymethod //11.1工厂方法模式 pattern/src/creation/...

    java高手真经 (UML建模+设计模式+面向服务架构) 卷7

    综合实例——Bug管理系统 (3)设计模式样例(24个讲解样例程序) pattern/src/principle/liskovsubstitution//10.3.2里氏代换原则 pattern/src/creation/factorymethod //11.1工厂方法模式 pattern/src/creation/...

    java高手真经 (UML建模+设计模式+面向服务架构) 卷2

    (3)设计模式样例(24个讲解样例程序) pattern/src/principle/liskovsubstitution//10.3.2里氏代换原则 pattern/src/creation/factorymethod //11.1工厂方法模式 pattern/src/creation/abstractfactory //11.2抽象...

    java高手真经 (UML建模+设计模式+面向服务架构) 卷4

    (3)设计模式样例(24个讲解样例程序) pattern/src/principle/liskovsubstitution//10.3.2里氏代换原则 pattern/src/creation/factorymethod //11.1工厂方法模式 pattern/src/creation/abstractfactory //11.2抽象...

    设计模式Demo

    行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。 其实还有两类:并发型模式和线程池模式。 二、设计...

Global site tag (gtag.js) - Google Analytics