行为型-访问者模式(Visitor Pattern)

说明

访问者模式(Visitor Pattern)是一种行为型设计模式,它允许在不改变已有对象结构的情况下,定义新的操作。

在软件开发中,有时需要对一个复杂的对象结构中的各个元素进行不同的操作,例如,计算对象结构中元素的总和、对每个元素进行特定的处理等。如果直接在对象结构的类中定义这些操作,将会导致类的耦合度高,代码维护困难。

访问者模式通过将操作封装在一个访问者类中,使得可以在不改变对象结构的情况下,对对象结构中的每个元素应用不同的操作。访问者模式将数据结构和操作分离,提高了系统的可扩展性和可维护性。

组成部分:

  • 抽象访问者(Visitor):声明访问对象结构中各个元素的操作方法,通过不同的具体访问者来实现不同的操作。
  • 具体访问者(ConcreteVisitor):实现抽象访问者中定义的操作方法,完成对对象结构中不同元素的具体操作。
  • 抽象元素(Element):声明接受访问者访问的方法,以及可能被访问者访问的其他方法。
  • 具体元素(ConcreteElement):实现抽象元素中声明的方法,确定访问者访问时的具体行为。
  • 对象结构(Object Structure):由多个元素组成的复杂对象,提供一个接受访问者访问的方法。

优点:

  • 将数据结构与操作分离,提高了可扩展性和可维护性。
  • 新增操作时,只需要添加具体访问者类即可,无需修改现有代码。
  • 访问者模式符合开闭原则,对扩展开放,对修改关闭。

缺点:

  • 增加新的元素类时,需要修改抽象访问者的接口,导致所有具体访问者类都需要进行修改。

使用场景:

  • 对象结构相对稳定,但经常需要在对象结构中定义新的操作。
  • 需要对一个对象结构中的元素进行多种不相关的操作。
  • 对象结构中的元素数目比较少,但其操作频繁变化。

示例

一个常见的实际应用场景是文件系统的访问。假设我们要实现一个文件系统浏览器,可以浏览文件夹和文件,并对其进行不同的操作,例如统计文件夹大小、查找特定文件等。

在这个场景中,我们可以使用访问者模式。具体的实现中,抽象访问者接口可以定义访问文件夹和文件的方法,具体访问者类可以实现这些方法来完成不同的操作。抽象元素接口可以定义接受访问者的方法,具体元素类可以实现这个方法并把访问者传递给具体元素的子元素,以便它们也能接受访问者的访问。

首先,定义抽象访问者接口Visitor

public interface Visitor {
    void visit(File file);
    void visit(Folder folder);
}

然后,定义抽象元素接口Element

public interface Element {
    void accept(Visitor visitor);
}

接下来,实现具体的元素类FileFolder,并在实现类中实现接受访问者的方法:

public class File implements Element {
    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;
    }

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

public class Folder implements Element {
    private String name;
    private List children;

    public Folder(String name) {
        this.name = name;
        this.children = new ArrayList<>();
    }

    public void addChild(Element element) {
        children.add(element);
    }

    public String getName() {
        return name;
    }

    public List getChildren() {
        return children;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
        for (Element child : children) {
            child.accept(visitor);
        }
    }
}

然后,实现具体的访问者类SizeVisitor,用于统计文件夹大小:

public class SizeVisitor implements Visitor {
    private int totalSize;

    public int getTotalSize() {
        return totalSize;
    }

    @Override
    public void visit(File file) {
        totalSize += file.getSize();
    }

    @Override
    public void visit(Folder folder) {
        // 访问文件夹时不做任何操作
    }
}

最后,我们可以创建文件和文件夹对象,并使用访问者来对文件系统进行操作:

public class VisitorExample {
    public static void main(String[] args) {
        // 创建文件系统
        Folder root = new Folder("root");
        File file1 = new File("file1.txt", 10);
        File file2 = new File("file2.txt", 20);
        Folder folder1 = new Folder("folder1");
        File file3 = new File("file3.txt", 15);
        File file4 = new File("file4.txt", 25);

        // 构建文件系统结构
        root.addChild(file1);
        root.addChild(file2);
        root.addChild(folder1);
        folder1.addChild(file3);
        folder1.addChild(file4);

        // 创建访问者
        SizeVisitor visitor = new SizeVisitor();

        // 让访问者访问文件系统
        root.accept(visitor);

        // 获取文件夹大小
        System.out.println("Total Size: " + visitor.getTotalSize());
    }
}

运行结果

Total Size: 70

你可能感兴趣的:(探索设计模式,访问者模式,设计模式)