Visitor模式可以用来把数据结构与处理分离开。通俗来说就是编写一个访问者类来访问数据结构中的元素,并把对各元素的处理交给访问者类。这样,当需要增加新的处理时,只需要编写新的访问者,然后让数据结构可以接受访问者的访问即可。

  下面先看示例程序的类图。

  在示例程序中,使用Composite模式中用到了那个文件和文件夹的例子作为访问者要访问的数据结构。访问者会访问由文件和文件夹构成的数据结构,然后显示出文件和文件夹的一览。

 package bigjunoba.bjtu.visitor;

 public abstract class Visitor {
public abstract void visit(File file);
public abstract void visit(Directory directory);
}

  Visitor类是表示访问者的抽象类。访问者依赖于它所访问的数据结构(即File类和Directory类)。这里visit方法用到了重载,分别表示了用于访问文件和文件夹的方法。

 package bigjunoba.bjtu.visitor;

 public interface Element {
public abstract void accept(Visitor v);
}

  Element接口是接受访问者的访问的接口。accept方法的参数是访问者Visitor类。

 package bigjunoba.bjtu.visitor;

 import java.util.Iterator;

 public abstract class Entry implements Element {
public abstract String getName(); // 获取名字
public abstract int getSize(); // 获取大小
public Entry add(Entry entry) throws FileTreatmentException { // 增加目录条目
throw new FileTreatmentException();
}
public Iterator<Element> iterator() throws FileTreatmentException { // 生成Iterator
throw new FileTreatmentException();
}
public String toString() { // 显示字符串
return getName() + " (" + getSize() + ")";
}
}

  Entry类与Composite模式中的Entry类是一样的,不过该Entry类实现了Element接口,这是为了让Entry类适用于Visitor模式。实际上实现Element接口中声明的抽象方法accept的是Entry类的子类。

  add方法仅对Directory类有效,因此在Entry类中,让它简单地报错。同样,用于获取Iterator的iterator方法也仅对Directory类有效,也让它简单地报错。

 package bigjunoba.bjtu.visitor;

 public class File extends Entry {
private String name;
private int size;
public File(String name, int size) {
this.name = name;
this.size = size;
}
public String getName() {
return name;
}
public int getSize() {
return size;
}
public void accept(Visitor v) {
v.visit(this);
}
}

  File类中要注意的是它是如何实现accept接口的。accept方法的参数是Visitor类,然后调用Visitor类的visit方法,由于这里的this是File类的实例,所以调用的是第一个visit方法。

 package bigjunoba.bjtu.visitor;

 import java.util.Iterator;
import java.util.ArrayList; public class Directory extends Entry {
private String name; // 文件夹名字
private ArrayList<Entry> dir = new ArrayList<Entry>(); // 目录条目集合
public Directory(String name) { // 构造函数
this.name = name;
}
public String getName() { // 获取名字
return name;
}
public int getSize() { // 获取大小
int size = 0;
Iterator<Entry> it = dir.iterator();
while (it.hasNext()) {
Entry entry = (Entry)it.next();
size += entry.getSize();
}
return size;
}
public Entry add(Entry entry) { // 增加目录条目
dir.add(entry);
return this;
}
public Iterator iterator() { // 生成Iterator
return dir.iterator();
}
public void accept(Visitor v) { // 接受访问者的访问
v.visit(this);
}
}

  同File类一样,调用visit的第一个方法,告诉访问者“当前正在访问的是Directory类的实例”。

 package bigjunoba.bjtu.visitor;

 import java.util.Iterator;

 public class ListVisitor extends Visitor {
private String currentdir = ""; // 当前访问的文件夹的名字
public void visit(File file) { // 在访问文件时被调用
System.out.println(currentdir + "/" + file);
}
public void visit(Directory directory) { // 在访问文件夹时被调用
System.out.println(currentdir + "/" + directory);
String savedir = currentdir;
currentdir = currentdir + "/" + directory.getName();
Iterator it = directory.iterator();
while (it.hasNext()) {
Entry entry = (Entry)it.next();
entry.accept(this);
}
currentdir = savedir;
}
}

  ListVisitor类是访问数据结构并显示元素一览。visit(Directory directory)方法,遍历文件夹中的所有目录条目并调用它们各自的accept方法,然后accept方法调用visit方法,visit方法又会调用accept方法,这样就形成了非常复杂的递归调用。通常的递归调用是某个方法调用自身,在Visitor模式中,则是accept方法与visit方法之间相互调用。

 package bigjunoba.bjtu.visitor;

 public class FileTreatmentException extends RuntimeException {
public FileTreatmentException() {
}
public FileTreatmentException(String msg) {
super(msg);
}
}

  处理异常类。

 package bigjunoba.bjtu.visitor;

 public class Main {
public static void main(String[] args) {
try {
System.out.println("Making root entries...");
Directory rootdir = new Directory("root");
Directory bindir = new Directory("bin");
Directory tmpdir = new Directory("tmp");
Directory usrdir = new Directory("usr");
rootdir.add(bindir);
rootdir.add(tmpdir);
rootdir.add(usrdir);
bindir.add(new File("vi", 10000));
bindir.add(new File("latex", 20000));
rootdir.accept(new ListVisitor()); System.out.println("");
System.out.println("Making user entries...");
Directory yuki = new Directory("yuki");
Directory hanako = new Directory("hanako");
Directory tomura = new Directory("tomura");
usrdir.add(yuki);
usrdir.add(hanako);
usrdir.add(tomura);
yuki.add(new File("diary.html", 100));
yuki.add(new File("Composite.java", 200));
hanako.add(new File("memo.tex", 300));
tomura.add(new File("game.doc", 400));
tomura.add(new File("junk.mail", 500));
rootdir.accept(new ListVisitor());
} catch (FileTreatmentException e) {
e.printStackTrace();
}
}
}

  这里和Composite模式做比较,Composite模式中调用printList方法来显示文件夹中的内容,该方法已经在Directory类(即表示数据结构的类)中实现了。而在Visitor模式中是在访问者中显示文件夹中的内容。这是因为显示文件夹中的内容业数据对数据结构中的各元素进行的处理。

Making root entries...
/root (30000)
/root/bin (30000)
/root/bin/vi (10000)
/root/bin/latex (20000)
/root/tmp (0)
/root/usr (0) Making user entries...
/root (31500)
/root/bin (30000)
/root/bin/vi (10000)
/root/bin/latex (20000)
/root/tmp (0)
/root/usr (1500)
/root/usr/yuki (300)
/root/usr/yuki/diary.html (100)
/root/usr/yuki/Composite.java (200)
/root/usr/hanako (300)
/root/usr/hanako/memo.tex (300)
/root/usr/tomura (900)
/root/usr/tomura/game.doc (400)
/root/usr/tomura/junk.mail (500)

  运行结构和Composite模式中的运行结果一样。

设计模式(十三)Visitor模式的更多相关文章

  1. 设计模式 ( 十三 ) 命令模式Command(对象行为型)

    设计模式 ( 十三 ) 命令模式Command(对象行为型) 1.概述         在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需 ...

  2. 设计模式之visitor模式,人人能懂的有趣实例

    设计模式,现在在网上随便搜都一大堆,为什么我还要写"设计模式"的章节呢? 两个原因: 1.本人觉得这是一个有趣的设计模式使用实例,所以记下来: 2.看着设计模式很牛逼,却不知道怎么 ...

  3. 设计模式之——visitor模式

    visitor模式,又叫访问者模式,把结构和数据分开,编写一个访问者,去访问数据结构中的元素,然后把对各元素的处理全部交给访问者类.这样,当需要增加新的处理时候,只需要编写新的 访问者类,让数据结构可 ...

  4. 设计模式之Visitor模式(笔记)

    訪问者模式:表示一个作用于某个对象结构中的各元素操作.它使你能够不改变各元素的类的前提下定义作用于这些元素的新操作. 首先定义一个visitor抽象类,为每一个详细类声明一个visit操作 publi ...

  5. 设计模式:visitor模式

    核心:将数据结构和数据的处理分开 注意:注意函数的参数传递和调用关系 例子: class Element; class Visitor { public: virtual void Visit(Ele ...

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

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

  7. 乐在其中设计模式(C#) - 访问者模式(Visitor Pattern)

    原文:乐在其中设计模式(C#) - 访问者模式(Visitor Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 访问者模式(Visitor Pattern) 作者:webabc ...

  8. 设计模式:基于线程池的并发Visitor模式

    1.前言 第二篇设计模式的文章我们谈谈Visitor模式. 当然,不是简单的列个的demo,我们以电商网站中的购物车功能为背景,使用线程池实现并发的Visitor模式,并聊聊其中的几个关键点. 一,基 ...

  9. 设计模式---行为变化模式之访问器模式(Visitor)

    一:概念 访问者模式,是行为模式之一,它分离对象的数据和行为,使用Visitor模式,可以不修改已有类的情况下,增加新的操作角色和职责. 二:动机 在软件构建的过程中,由于需求的改变,某些类层次结构中 ...

随机推荐

  1. 【已解决】关于IDEA中 Tomcat 控制台打印日志中文乱码的解决

    在 Idea 上面使用 Tomcat 时,发现控制台打印信息的时候,出行中文乱码问题; 可以通过以下几种解决办法 1:在-Dfile.encoding=UTF-8 在vm中设置编码方式 2.然后从Fi ...

  2. 品Spring:SpringBoot发起bean定义注册的“二次攻坚战”

    上一篇文章整体非常轻松,因为在容器启动前,只注册了一个bean定义,就是SpringBoot的主类. OK,今天接着从容器的启动入手,找出剩余所有的bean定义的注册过程. 具体细节肯定会颇为复杂,同 ...

  3. python-电脑结构、网络基础、单位转换

    目录 一.计算机五大部件 二.程序运行的过程 三.ARP协议 四.单位转换 一.计算机五大部件 电脑之父——冯·诺伊曼提出了计算机的五大部件:输入设备.输出设备.存储器.运算器和控制器. 我们把键盘和 ...

  4. Maven 梳理 - 常用三种archetype说明

    archetype:原型的意思,可理解为Maven项目模板工具包 常用archetype 1.cocoon-22-archetype-webapp 2.maven-archetype-quicksta ...

  5. 读《深入理解Elasticsearch》点滴-改善查询相关性

    1.标准查询 query match _all query:"搜索字符串" operator:or 2.多匹配查询+区分权重 query multi_match "que ...

  6. Linux 查看端口状态netstat

    netstat命令参数: -t : 指明显示TCP端口 -u : 指明显示UDP端口 -l : 仅显示监听套接字(所谓套接字就是使应用程序能够读写与收发通讯协议(protocol)与资料的程序) -p ...

  7. spring和springmvc的基础知识点

    1.spring中使用@Service("userservice")如何在其他地方引用这个service? (1)getBean("userservice") ...

  8. 02-18 scikit-learn库之k近邻算法

    目录 scikit-learn库之k近邻算法 一.KNeighborsClassifier 1.1 使用场景 1.2 代码 1.3 参数详解 1.4 方法 1.4.1 kneighbors([X, n ...

  9. Spring Boot2 系列教程(十一)Spring Boot 中的静态资源配置

    当我们使用 SpringMVC 框架时,静态资源会被拦截,需要添加额外配置,之前老有小伙伴在微信上问松哥 Spring Boot 中的静态资源加载问题:"松哥,我的 HTML 页面好像没有样 ...

  10. 第10项:重写equals时请遵守通用约定

      重写equals方法看起来似乎很简单,但是有许多重写方式会导致错误,而且后果非常严重.最容易避免这类问题的办法就是不覆盖equals方法,在这种情况下,类的每个实例都只能与它自身相等.如果满足了以 ...