图解设计模式 - Visitor 模式

Visitor模式将数据结构与处理分离,增加新的处理方式无需修改数据类。该模式通过Element接受Visitor访问,实现双重分发,符合开闭原则。以文件夹和文件为例,ListVisitor可以访问并处理二者,展示文件名和大小。
摘要由CSDN通过智能技术生成

读书笔记 仅供参考

简述

通常将数据结构和处理数据的代码放到同一个类中,但是如果有多种处理方式,增加处理方式就会多次修改数据类。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 符合开闭原则:对扩展开发,对修改关闭。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java设计模式是一组经过实践验证的面向对象设计原则和模式,可以帮助开发人员解决常见的软件设计问题。下面是常见的23种设计模式: 1. 创建型模式(Creational Patterns): - 工厂方法模式(Factory Method Pattern) - 抽象工厂模式(Abstract Factory Pattern) - 单例模式(Singleton Pattern) - 原型模式(Prototype Pattern) - 建造者模式(Builder Pattern) 2. 结构型模式(Structural Patterns): - 适配器模式(Adapter Pattern) - 桥接模式(Bridge Pattern) - 组合模式(Composite Pattern) - 装饰器模式(Decorator Pattern) - 外观模式(Facade Pattern) - 享元模式(Flyweight Pattern) - 代理模式(Proxy Pattern) 3. 行为型模式(Behavioral Patterns): - 责任链模式(Chain of Responsibility Pattern) - 命令模式(Command Pattern) - 解释器模式(Interpreter Pattern) - 迭代器模式(Iterator Pattern) - 中介者模式(Mediator Pattern) - 备忘录模式(Memento Pattern) - 观察者模式(Observer Pattern) - 状态模式(State Pattern) - 策略模式(Strategy Pattern) - 模板方法模式(Template Method Pattern) - 访问者模式Visitor Pattern) 4. 并发型模式(Concurrency Patterns): - 保护性暂停模式(Guarded Suspension Pattern) - 生产者-消费者模式(Producer-Consumer Pattern) - 读写锁模式(Read-Write Lock Pattern) - 信号量模式(Semaphore Pattern) - 线程池模式(Thread Pool Pattern) 这些设计模式可以根据问题的特点和需求来选择使用,它们提供了一些可复用的解决方案,有助于开发高质量、可维护且易于扩展的软件系统。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值