Visitor模式

Visitor 模式

在Visitor 模式中,数据结构和处理被分离开。我们编写一个表示“访问者”的类来访问数据结构中的元素,并把对各元素的处理交给访问者类。这样,当需要增加新的处理时,我们只需要编写新的访问者,然后让数据结构可以接受访问者的访问即可

示例程序

示例程序类图

类图

Visitor
public abstract class Visitor {
    public abstract void visit(File file);
    public abstract void visit(Directory directory);
}
Element
public interface Element {
    void accept(Visitor v);
}
Entry
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 iterator() throws FileTreatmentException {    // 生成Iterator
        throw new FileTreatmentException();
    }
    @Override
    public String toString() {                                          // 显示字符串
        return getName() + " (" + getSize() + ")";
    }
}
File
public class File extends Entry {
    private String name;
    private int size;
    public File(String name, int size) {
        this.name = name;
        this.size = size;
    }
    @Override
    public String getName() {
        return name;
    }
    @Override
    public int getSize() {
        return size;
    }
    @Override
    public void accept(Visitor v) {
        v.visit(this);
    }
}
Directory
import java.util.Iterator;
import java.util.ArrayList;

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

public class ListVisitor extends Visitor {
    private String currentdir = "";                         // 当前访问的文件夹的名字
    @Override
    public void visit(File file) {                  // 在访问文件时被调用
        System.out.println(currentdir + "/" + file);
    }
    @Override
    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;
    }
}
FileTreatmentException
public class FileTreatmentException extends RuntimeException {
    public FileTreatmentException() {
    }
    public FileTreatmentException(String msg) {
        super(msg);
    }
}
Main
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();
        }
    }
}

Visitor模式中登场的角色

1.Visitor(访问者)

Visitor角色负责对数据结构中每个具体的元素(ConcreteElement角色)声明一个用于访问xxxxx的visit(xxxxx)方法。visit(xxxxx)是用于处理xxxxx的方法,负责实现该方法的是ConcreteVisitor角色。在示例程序中,由Visitor类扮演此角色。

2.ConcreteVisitor(具体的访问者)

ConcreteVisitor角色负责实现Visitor角色所定义的接口(API)。它要实现所有的visit(xxxxx)方法,即实现如何处理每个ConcreteElement角色。在示例程序中,由ListVisitor类扮演此角色。如同在ListVisitor中,currentdir字段的值不断发生变化一样,随着visit(xxxxx)处理的进行,ConcreteVisitor角色的内部状态也会不断地发生变化。

3.Element(元素)

Element角色表示Visitor角色的访问对象。它声明了接受访问者的accept方法。accept方法接收到的参数是Visitor角色。在示例程序中,由Element接口扮演此角色。

4.ConcreteElement

ConcreteElement角色负责实现Element角色所定义的接口(API)。在示例程序中,由File类和Directory类扮演此角色。

5.ObjectStructure(对象结构)

ObjectStructure角色负责处理Element角色的集合。ConcreteVisitor角色为每个Element角色都准备了处理方法。在示例程序中,由Directory类扮演此角色(一人分饰两角)。为了让ConcreteVisitor角色可以遍历处理每个Element角色,在示例程序中,我们在Directory类中实现了iterator方法。

通用类图

通用类图

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值