图解设计模式

来源:互联网 发布:神仙淘宝店txt下载 编辑:程序博客网 时间:2024/06/02 05:35

读书笔记 仅供参考

简述

通常将数据结构和处理数据的代码放到同一个类中,但是如果有多种处理方式,增加处理方式就会多次修改数据类。Visitor 模式(访问者模式)将数据结构与处理分离开来,增加新的处理时,只需要编写新的访问者就可以了。

UML 和角色

Visitor

负责对数据结构中每个具体的元素(ConcreteElement 角色)声明一个用于访问的 visit 方法。

ConcreteVisitor

负责实现 Visitor 角色定义的接口(API),要实现所有的 visit 方法。

Element

表示 Visitor 觉得访问对象,声明了接收访问者的 accept 方法。accept 方法的参数是 Visitor 角色。

ConcreteElement

负责实现 Element 角色定义的接口(API)。

ObjectStructure

负责处理 Element 角色的集合。

UML

这里写图片描述

例子

例程是一个访问文件夹和文件,显示文件名和大小的程序。ListVisitor 作为访问者,拥有两个方法,visit(File) 和 visit(Directory),将 ListVisitor 比作一个寻求帮助的人,那么 FIle 和 Directory 就是两个家庭(他们都属于家庭,虽然不一样)。当他们选择接收(accept 方法)访问者时,访问者就根据家庭的不同干不同的事(visit 方法)。

//表示访问者的抽象类,依赖于访问的数据结构public abstract class Visitor {    //根据不同的参数调用不同的访问方法    public abstract void visit(File file);    public abstract void visit(Directory directory);}
//访问数据结构并显示数据一览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<Entry> it = directory.iterator();        while (it.hasNext()) {            Entry entry = it.next();            entry.accept(this);        }        currentDir = saveDir;    }}
public interface Element {    void accept(Visitor visitor);}
//相当于 Composite 模式的父类,在 Visitor 模式中使用并不是必须的//真正作为被访问者的是它的子类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 String toString() {        return getName() + " (" + getSize() + ")";    }}
// 作为被访问的元素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    //告诉 Visitor 正在访问的对象是 File 的实例    public void accept(Visitor visitor) {        visitor.visit(this);    }}
public class Directory extends Entry {    private String name;    private List<Entry> dir = new ArrayList<>();    public Directory(String name) {        this.name = name;    }    @Override    public String getName() {        return name;    }    @Override    public int getSize() {        int size = 0;        Iterator<Entry> it = dir.iterator();        while (it.hasNext()) {            Entry entry = it.next();            size += entry.getSize();        }        return size;    }    @Override    public Entry add(Entry entry) throws FileTreatmentException {        dir.add(entry);        return this;    }    public Iterator<Entry> iterator() {        return dir.iterator();    }    @Override    public void accept(Visitor visitor) {        visitor.visit(this);    }}
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();        }    }}

运行结果

这里写图片描述

UML

这里写图片描述

要点

双重分发

像在 Visitor 模式中两个角色共同决定了实际进行的处理的消息分发的方式被称为双重分发。

开闭原则

Visitor 符合开闭原则:对扩展开发,对修改关闭。

原创粉丝点击