设计模式——访问者模式

访问者模式(Visitor Pattern)是一种行为型设计模式,它主要用于在不修改现有类结构的前提下向对象结构添加新的操作。访问者模式通过定义一个访问者接口,使得可以在不改变元素类的情况下,为各个元素类增加新的功能。

原理

  • 元素接口(Element Interface): 定义了一个accept()方法,用于接收访问者对象的访问。
  • 具体元素类(Concrete Elements): 实现了元素接口,并且每个类都可能有自己特有的业务逻辑和数据。
  • 访问者接口(Visitor Interface): 定义了一系列访问元素的方法,对应不同的具体元素类型。
  • 具体访问者类(Concrete Visitors): 实现了访问者接口,提供了对每个具体元素类进行特定操作的方法。

Java代码示例

java 复制代码
// 元素接口
public interface Element {
    void accept(Visitor visitor);
}

// 具体元素类 - 文件
public class File implements Element {
    private String name;
    
    public File(String name) {
        this.name = name;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visitFile(this);
    }
    
    // 获取文件名
    public String getName() {
        return name;
    }
}

// 具体元素类 - 文件夹
public class Folder implements Element {
    private List<Element> children;
    
    public Folder() {
        this.children = new ArrayList<>();
    }

    public void addElement(Element child) {
        children.add(child);
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visitFolder(this);
        for (Element child : children) {
            child.accept(visitor);
        }
    }
    
    // 获取子元素列表
    public List<Element> getChildren() {
        return children;
    }
}

// 访问者接口
public interface Visitor {
    void visitFile(File file);
    void visitFolder(Folder folder);
}

// 具体访问者类 - 计算文件总数与大小
public class SizeCalculator implements Visitor {
    private int fileCount;
    private long totalSize;

    public SizeCalculator() {
        fileCount = 0;
        totalSize = 0L;
    }

    @Override
    public void visitFile(File file) {
        fileCount++;
        // 假设我们已有一个获取文件大小的方法
        totalSize += getFileSize(file.getName());
    }

    @Override
    public void visitFolder(Folder folder) {
        for (Element element : folder.getChildren()) {
            element.accept(this);
        }
    }

    public int getFileCount() {
        return fileCount;
    }

    public long getTotalSize() {
        return totalSize;
    }

    // 示例方法,实际中需要从磁盘或数据库获取
    private long getFileSize(String fileName) {
        // 这里仅作演示,实际上会根据文件名获取真实大小
        return 1024; // 假设每个文件大小为1KB
    }
}

// 使用示例
public class Client {
    public static void main(String[] args) {
        Folder root = new Folder();
        root.addElement(new File("file1.txt"));
        root.addElement(new File("file2.txt"));
        Folder subFolder = new Folder();
        subFolder.addElement(new File("subFile1.txt"));
        root.addElement(subFolder);

        SizeCalculator calculator = new SizeCalculator();
        root.accept(calculator);

        System.out.println("Total files: " + calculator.getFileCount());
        System.out.println("Total size: " + calculator.getTotalSize());
    }
}

想象你正在管理一个图书馆,书架上有各种书籍和盒子(代表文件和文件夹)。当你要统计所有书籍的数量和总体积时,你可以扮演"访问者"的角色,逐个检查每本书籍和盒子。打开盒子后,再继续检查盒子里的内容。在这个过程中,你不需要修改书本或盒子本身,而是通过定义一套针对不同对象的操作规则(访问者接口),实现了灵活的功能扩展。

应用场景

  • 文件系统遍历:定义一个访问者来统计文件夹中的文件数量、计算总大小等。
  • 编译器语法分析:遍历抽象语法树(AST),对不同类型的节点执行不同的处理,如类型检查、代码生成等。

适用性

  • 对象结构稳定但需要频繁增加新的操作。
  • 需要对一组相似的对象结构执行不同的操作。
  • 想要在不影响这些对象的情况下定义新操作。
相关推荐
virus59457 小时前
悟空CRM mybatis-3.5.3-mapper.dtd错误解决方案
java·开发语言·mybatis
没差c8 小时前
springboot集成flyway
java·spring boot·后端
时艰.8 小时前
Java 并发编程之 CAS 与 Atomic 原子操作类
java·开发语言
编程彩机8 小时前
互联网大厂Java面试:从Java SE到大数据场景的技术深度解析
java·大数据·spring boot·面试·spark·java se·互联网大厂
笨蛋不要掉眼泪8 小时前
Spring Boot集成LangChain4j:与大模型对话的极速入门
java·人工智能·后端·spring·langchain
Yvonne爱编码9 小时前
JAVA数据结构 DAY3-List接口
java·开发语言·windows·python
像少年啦飞驰点、10 小时前
零基础入门 Spring Boot:从“Hello World”到可上线微服务的完整学习指南
java·spring boot·微服务·编程入门·后端开发
眼眸流转10 小时前
Java代码变更影响分析(一)
java·开发语言
Yvonne爱编码10 小时前
JAVA数据结构 DAY4-ArrayList
java·开发语言·数据结构
阿猿收手吧!10 小时前
【C++】C++原子操作:compare_exchange_weak详解
java·jvm·c++