每天学一个设计模式13——访问者模式

访问者模式(访问数据结构并处理数据)

用处

将数据结构与处理分离开来。

角色

  • Visitor(访问者)
    该角色负责对数据结构中每个具体的元素e(ConcreteElement角色)声明一个用于访问e的visit(e)方法。visit(e)是用于处理e的方法,负责实现该方法的是ConcreteVisitor角色。
  • ConcreteVisitor(具体的访问者)
    该角色负责实现Visitor角色所定义的方法(API)。它要实现所有的visit(e)方法,即如何处理每个ConcreteElement角色。
  • Element
    该角色表示Visitor角色的访问对象。它声明了访问者的accept方法。accept方法接受到的参数是Visitor角色。
  • ConcreteElement
    该角色负责实现Visitor角色的访问对象,它声明了接受访问者的accept方法。accept方法接收到的参数是Visitor角色。
  • ObjectStructure
    该角色负责处理Element角色的集合。ConcreteVisitor角色为每个Element角色都准备了处理方法。

类图

在这里插入图片描述 这个类图其实没太看懂,个人认为Element和Visitor有个依赖关系。

  • Visitor接口被ConcreteVisitor类实现并在visitor方法中处理数据结构
  • Element接口中聚合了ObjectStructure类(需要访问的数据结构)
  • ConcreteElement类接受Visitor对象作为参数,并调用Visitor对象的visit方法将自身this作为参数传入,实现双委派。

举例

//Client角色
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.printList("");
            rootdir.accept(new ListVisitor());

            System.out.println("");
            System.out.println("Making user entries");
            Directory yuki = new Directory("yuki");
            Directory hanako = new Directory("hanako");
            Directory tomaru = new Directory("tomaru");
            usrdir.add(yuki);
            usrdir.add(hanako);
            usrdir.add(tomaru);
            yuki.add(new File("diary.html",100));
            yuki.add(new File("Composite.java",200));
            hanako.add(new File("memo.tex",300));
            tomaru.add(new File("game.doc",400));
            tomaru.add(new File("junk.mail",500));
//            rootdir.printList("");
            rootdir.accept(new ListVisitor());
        }catch(FileTreatmentException e){
            e.printStackTrace();
        }
    }

}

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


//ConcreteVisitor角色
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;
    }
}
//Element角色
interface Element{
    void accept(Visitor v);
}

class FileTreatmentException extends RuntimeException{
    public FileTreatmentException(){

    }
    public FileTreatmentException(String msg){
        super(msg);
    }
}

//ConcreteElement角色
abstract class Entry implements Element{
    public abstract String getName();
    public abstract int getSize();
    public Entry add(Entry entry) throws FileTreatmentException{
        throw new FileTreatmentException();
    }
//    protected abstract void printList(String prefix);
    public String toString(){
        return getName() + " ("+getSize()+")";
    }
    public Iterator iterator() throws FileTreatmentException{
        throw new FileTreatmentException();
    }
}


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;
    }
//    protected void printList(String prefix){
//        System.out.println(prefix + "/" +this);
//    }

    @Override
    public void accept(Visitor v) {
        v.visit(this); //双重委派
    }
}

class Directory extends Entry{
    private String name;
    private ArrayList directory = new ArrayList();
    public Directory(String name){
        this.name = name;
    }
    public String getName(){
        return name;
    }
    public int getSize(){
        int size = 0;
        Iterator it = directory.iterator();
        while(it.hasNext()){
            Entry entry = (Entry)it.next();
            size += entry.getSize();
        }
        return size;
    }
    public Entry add(Entry entry){
        directory.add(entry);
        return this;
    }
//    protected void printList(String prefix){
//        System.out.println(prefix +"/"+this);
//        Iterator it = directory.iterator();
//        while(it.hasNext()){
//            Entry entry = (Entry)it.next();
//            entry.printList(prefix + "/"+ name);
//        }
//    }


    @Override
    public Iterator iterator() throws FileTreatmentException {
        return directory.iterator();
    }

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

由被注释掉的部分,我们可以看出对数据结构处理的工作独立出来,在新增的LIstVisitor中完成。

在这里插入图片描述

总结

  • 符合开闭原则
  • 将处理从数据结构中分离,提高扩展性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑白程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值