Java案例中的访问者模式怎么写?

wen java案例 1

Java访问者模式案例

访问者模式(Visitor Pattern)是一种行为设计模式,它允许在不修改现有类结构的情况下,为这些类添加新的操作。

Java案例中的访问者模式怎么写?

核心角色

  • 抽象访问者(Visitor):声明每个具体元素类的访问方法
  • 具体访问者(ConcreteVisitor):实现每个访问方法
  • 抽象元素(Element):声明接受访问者的方法
  • 具体元素(ConcreteElement):实现接受方法
  • 对象结构(ObjectStructure):管理元素集合

完整案例:文件系统分析器

import java.util.ArrayList;
import java.util.List;
// ============ 抽象元素 ============
interface FileElement {
    void accept(Visitor visitor);
}
// ============ 具体元素 ============
// 文本文件
class TextFile implements FileElement {
    private String name;
    private int wordCount;
    public TextFile(String name, int wordCount) {
        this.name = name;
        this.wordCount = wordCount;
    }
    public String getName() { return name; }
    public int getWordCount() { return wordCount; }
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}
// 图片文件
class ImageFile implements FileElement {
    private String name;
    private int width;
    private int height;
    public ImageFile(String name, int width, int height) {
        this.name = name;
        this.width = width;
        this.height = height;
    }
    public String getName() { return name; }
    public int getWidth() { return width; }
    public int getHeight() { return height; }
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}
// 文件夹
class Folder implements FileElement {
    private String name;
    private List<FileElement> elements = new ArrayList<>();
    public Folder(String name) {
        this.name = name;
    }
    public String getName() { return name; }
    public void addElement(FileElement element) {
        elements.add(element);
    }
    public List<FileElement> getElements() {
        return elements;
    }
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}
// ============ 抽象访问者 ============
interface Visitor {
    void visit(TextFile textFile);
    void visit(ImageFile imageFile);
    void visit(Folder folder);
}
// ============ 具体访问者1:文件信息收集器 ============
class FileInfoCollector implements Visitor {
    private StringBuilder report = new StringBuilder();
    @Override
    public void visit(TextFile textFile) {
        report.append(String.format("文本文件: %s (字数: %d)%n", 
            textFile.getName(), textFile.getWordCount()));
    }
    @Override
    public void visit(ImageFile imageFile) {
        report.append(String.format("图片文件: %s (尺寸: %dx%d)%n", 
            imageFile.getName(), imageFile.getWidth(), imageFile.getHeight()));
    }
    @Override
    public void visit(Folder folder) {
        report.append(String.format("文件夹: %s%n", folder.getName()));
        for (FileElement element : folder.getElements()) {
            element.accept(this);
        }
    }
    public String getReport() {
        return report.toString();
    }
}
// ============ 具体访问者2:文件大小计算器 ============
class FileSizeCalculator implements Visitor {
    private long totalSize = 0;
    @Override
    public void visit(TextFile textFile) {
        // 假设每个字符占用2字节
        totalSize += textFile.getWordCount() * 2;
        System.out.println(textFile.getName() + " 大小: " + totalSize + " 字节");
    }
    @Override
    public void visit(ImageFile imageFile) {
        // 假设每个像素占用3字节
        totalSize += imageFile.getWidth() * imageFile.getHeight() * 3;
        System.out.println(imageFile.getName() + " 大小: " + totalSize + " 字节");
    }
    @Override
    public void visit(Folder folder) {
        System.out.println("进入文件夹: " + folder.getName());
        for (FileElement element : folder.getElements()) {
            element.accept(this);
        }
    }
    public long getTotalSize() {
        return totalSize;
    }
}
// ============ 对象结构 ============
class FileSystem {
    private List<FileElement> elements = new ArrayList<>();
    public void addElement(FileElement element) {
        elements.add(element);
    }
    public void accept(Visitor visitor) {
        for (FileElement element : elements) {
            element.accept(visitor);
        }
    }
}
// ============ 客户端 ============
public class VisitorPatternDemo {
    public static void main(String[] args) {
        // 创建文件系统结构
        Folder root = new Folder("项目文档");
        Folder srcFolder = new Folder("源代码");
        TextFile mainJava = new TextFile("Main.java", 500);
        TextFile utilsJava = new TextFile("Utils.java", 300);
        srcFolder.addElement(mainJava);
        srcFolder.addElement(utilsJava);
        Folder docsFolder = new Folder("文档");
        ImageFile diagram = new ImageFile("架构图.png", 1920, 1080);
        TextFile readme = new TextFile("README.md", 100);
        docsFolder.addElement(diagram);
        docsFolder.addElement(readme);
        root.addElement(srcFolder);
        root.addElement(docsFolder);
        // 使用不同的访问者
        System.out.println("===== 文件信息报告 =====");
        FileInfoCollector collector = new FileInfoCollector();
        root.accept(collector);
        System.out.println(collector.getReport());
        System.out.println("\n===== 文件大小计算 =====");
        FileSizeCalculator calculator = new FileSizeCalculator();
        root.accept(calculator);
        System.out.println("总大小: " + calculator.getTotalSize() + " 字节");
    }
}

简化版案例:动物园访客

// 抽象动物
interface Animal {
    void accept(ZooVisitor visitor);
}
// 具体动物
class Lion implements Animal {
    private String name;
    public Lion(String name) { this.name = name; }
    public String getName() { return name; }
    @Override
    public void accept(ZooVisitor visitor) {
        visitor.visit(this);
    }
}
class Elephant implements Animal {
    private String name;
    public Elephant(String name) { this.name = name; }
    public String getName() { return name; }
    @Override
    public void accept(ZooVisitor visitor) {
        visitor.visit(this);
    }
}
// 抽象访问者
interface ZooVisitor {
    void visit(Lion lion);
    void visit(Elephant elephant);
}
// 具体访问者:喂食员
class Feeder implements ZooVisitor {
    @Override
    public void visit(Lion lion) {
        System.out.println("喂食员给狮子 " + lion.getName() + " 喂肉");
    }
    @Override
    public void visit(Elephant elephant) {
        System.out.println("喂食员给大象 " + elephant.getName() + " 喂水果");
    }
}
// 具体访问者:清洁员
class Cleaner implements ZooVisitor {
    @Override
    public void visit(Lion lion) {
        System.out.println("清洁员清理狮子 " + lion.getName() + " 的笼子");
    }
    @Override
    public void visit(Elephant elephant) {
        System.out.println("清洁员清理大象 " + elephant.getName() + " 的场地");
    }
}
// 使用示例
public class ZooVisitorDemo {
    public static void main(String[] args) {
        List<Animal> animals = new ArrayList<>();
        animals.add(new Lion("辛巴"));
        animals.add(new Elephant("阿里"));
        ZooVisitor feeder = new Feeder();
        ZooVisitor cleaner = new Cleaner();
        System.out.println("=== 喂食时间 ===");
        for (Animal animal : animals) {
            animal.accept(feeder);
        }
        System.out.println("\n=== 清洁时间 ===");
        for (Animal animal : animals) {
            animal.accept(cleaner);
        }
    }
}

使用Lambda表达式优化

import java.util.function.Consumer;
// 简化版访问者模式
interface Shape {
    void accept(ShapeVisitor visitor);
}
class Circle implements Shape {
    private double radius;
    public Circle(double radius) { this.radius = radius; }
    public double getRadius() { return radius; }
    @Override
    public void accept(ShapeVisitor visitor) {
        visitor.visit(this);
    }
}
class Rectangle implements Shape {
    private double width, height;
    public Rectangle(double width, double height) { 
        this.width = width; 
        this.height = height; 
    }
    public double getWidth() { return width; }
    public double getHeight() { return height; }
    @Override
    public void accept(ShapeVisitor visitor) {
        visitor.visit(this);
    }
}
// 使用函数式接口
@FunctionalInterface
interface ShapeVisitor {
    void visit(Shape shape);
}
// 使用示例
public class LambdaVisitorDemo {
    public static void main(String[] args) {
        List<Shape> shapes = new ArrayList<>();
        shapes.add(new Circle(5));
        shapes.add(new Rectangle(3, 4));
        // 使用Lambda创建访问者
        ShapeVisitor areaCalc = shape -> {
            if (shape instanceof Circle) {
                Circle circle = (Circle) shape;
                System.out.println("圆面积: " + Math.PI * circle.getRadius() * circle.getRadius());
            } else if (shape instanceof Rectangle) {
                Rectangle rect = (Rectangle) shape;
                System.out.println("矩形面积: " + rect.getWidth() * rect.getHeight());
            }
        };
        shapes.forEach(shape -> shape.accept(areaCalc));
    }
}

访问者模式的优势

  1. 开闭原则:可以轻松添加新操作而不修改现有类
  2. 单一职责:将相关操作集中在一个访问者中
  3. 扩展性好:新操作只需添加新的访问者类

适用场景

  • 对象结构稳定但需要添加新操作
  • 需要对不同类型对象执行不相关的操作
  • 一个对象结构包含很多类,且这些类的接口不同

注意事项

  • 增加新元素类型困难(需要修改所有访问者)
  • 可能违反依赖倒置原则
  • 适用于结构稳定但操作多变的场景

访问者模式将数据结构与操作分离,使得算法可以独立于数据结构变化。

抱歉,评论功能暂时关闭!