「设计模式」访问者模式

209 阅读3分钟

一、概述

访问者模式(Visitor Pattern)是一个行为模式,封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新操作。

访问者模式主要解决的一个问题就是不用区分元素是哪种,而根据访问者的不同信息返回相应的信息,就好比文件夹中有文件,通过访问者的信息来判断你属于哪个文件夹。并也不用改变原有结构而很容易就实现了这种区别。

访问者模式在23个设计模式中,算是比较复杂而且晦涩难懂些。

访问者模式的5种角色:

抽象访问者(Visitor)角色:它定义了对每一个元素(Element)访问的行为,它的参数就是可以访问的元素。

具体访问者(ConcreteVisitor)角色:它需要给出对每一个元素类访问时所产生的具体行为。

抽象节点(Element)角色:它定义了一个接受访问者(accept)的方法,其意义是指,每一个元素都要可以被访问者访问。

具体节点(ConcreteElement)角色:它提供接受访问方法的具体实现,而这个具体的实现,通常情况下是使用访问者提供的访问该元素类的方法。

结构对象(ObjectStructure)角色:对象结构,通常包含多个访问对象。

二、优缺点

优点: 1、符合单一职责原则。 2、优秀的扩展性。 3、灵活性。

缺点: 1、具体元素对访问者公布细节,违反了迪米特原则。 2、具体元素变更比较困难。 3、违反了依赖倒置原则,依赖了具体类,没有依赖抽象。

三、实现方式

在我们系统盘里存放着大量的文件,通过文件夹去区分不同的类型,比如我现在有个“学习资料”和“工作文件”的文件夹,我们需要去访问文件夹去查找文件。

文件夹便是【访问者】,具体文件便是【节点元素】。

抽象访问者类(Folder)

public interface Folder {

    void visit(File file);

}

具体访问者类(StudyFolder/WorkFolder)

public class StudyFolder implements Folder{
    @Override
    public void visit(File file) {
        if(file instanceof StudyFile){
            System.out.println("[学习资料文件夹]下,已找到  "+ file.getName());
        }
    }
}

public class WorkFolder implements Folder{
    @Override
    public void visit(File file) {
        if(file instanceof WorkFile){
            System.out.println("[工作文件夹]下,已找到  "+ file.getName());
        }
    }
}

抽象元素类(File)

public abstract class File {

    private String name;

    public File(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    //接收
    public abstract void accept(Folder folder);
}

具体元素类(StudeyFile/WorderFile)

public class StudyFile extends File{


    public StudyFile(String name) {
        super(name);
    }

    @Override
    public void accept(Folder folder) {
        folder.visit(this);
    }

}

public class WorkFile extends File{


    public WorkFile(String name) {
        super(name);
    }

    @Override
    public void accept(Folder folder) {
        folder.visit(this);
    }
    
}

结构对象类(ObjectStructure)

public class ObjectStructure {

    List<File> list = new ArrayList<>();

    public void add(File file){
        list.add(file);
    }
    public void action(Folder folder){
        for (File file : list) {
            file.accept(folder);
        }
    }

}

客户端(Client)

public class client {
    public static void main(String[] args) {
        File studyFile = new StudyFile("Python学习资料");
        File workFile = new WorkFile("旅游项目文件");


        ObjectStructure objectStructure = new ObjectStructure();
        objectStructure.add(studyFile);
        objectStructure.add(workFile);

        Folder studyFolder = new StudyFolder();
        Folder workFolder = new WorkFolder();

        objectStructure.action(studyFolder);
        objectStructure.action(workFolder);
    }
}

结果输出

[学习资料文件夹]下,已找到  Python学习资料
[工作文件夹]下,已找到  旅游项目文件

四、常见应用场景

  • 对象结构相对稳定,但其操作算法经常变化的程序。
  • 对象结构中的对象需要提供多种不同且不相关的操作,而且要避免让这些操作的变化影响对象的结构。