设计模式之美

访问者模式

Posted by 月光下的海 on August 12, 2022

访问者模式的概念

  • 将一个或多个操作应用到一组对象上,用来解耦操作和该对象本身。

访问者模式的使用场景

  • 比如我们目前有这样一个需求,要提取一组文件中的文本内容(假设这一组文件包括PDF、Excel以及TXT文件),用访问者模式实现大概是下面这个样子。

代码实现

  • 定义访问者接口,其中提供三个方法,分别用来处理三种不同格式的文件
public interface Visitor {
    void visit(PdfFile pdfFile);
    void visit(ExcelFile excelFile);
    void visit(TxtFile txtFile);
}
  • 定义一个要访问对象的基类,暂且叫做ResourceFile,提供一个accept方法,用来接收访问者对象。
public abstract class ResourceFile {
    public String filePath;
    
    public ResourceFile(String filePath){
        this.filePath = filePath;
    }
    abstract void accept(Visitor visitor);
}

  • 定义用来描述三种不同格式文件的class,并且继承上面定义的基类
public class PdfFile extends ResourceFile{
    public PdfFile(String filePath) {
        super(filePath);
    }

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

public class ExcelFile extends ResourceFile{

    public ExcelFile(String filePath) {
        super(filePath);
    }

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

public class TxtFile extends ResourceFile{
    public TxtFile(String filePath) {
        super(filePath);
    }

    @Override
    void accept(Visitor visitor) {
        visitor.visit(this);
    }
}
  • 定义一个叫做抽取器的类,用来完成抽取文件中文本内容的功能
public class Extractor implements Visitor{

    @Override
    public void visit(PdfFile pdfFile) {
        System.out.println("extract pdf file...");
    }

    @Override
    public void visit(ExcelFile excelFile) {
        System.out.println("extract excel file...");
    }

    @Override
    public void visit(TxtFile txtFile) {
        System.out.println("extract txt file...");
    }
}
  • 客户端使用
public class Application {
    public static void main(String[] args) {
        Visitor visitor = new Extractor();
        for (ResourceFile resourceFile : collectResourceFile()) {
            resourceFile.accept(visitor);
        }
    }

    public static List<ResourceFile> collectResourceFile(){
        return new ArrayList<ResourceFile>();
    }

    private static ResourceFile txtResource() {
        return new TxtFile("txt");
    }

    private static ResourceFile excelResource() {
        return new ExcelFile("excel");
    }

    private static ResourceFile pdfResource() {
        return new PdfFile("pdf");
    }
}
extract pdf file...
extract excel file...
extract txt file...

总结

  • 通常来说,访问者模式针对于一组类型不同、但是却有一些共性的对象(比如说例子中的三种不同格式文件,共性就是都是文件-会有同一个基类或者实现同一个接口),在不同的应用场景下需要有一些业务上的操作 ,比如说提取文本内容,或者说后续还有其他需求(假设需要做文件的压缩)。如果将这些操作都放在每个类自身中,随着需求的迭代、功能的增加,该类可能会膨胀,职责上划分会越来越不单一。因此我们可以使用访问者模式 将对这些对象本身的业务操作从该对象中抽离出来,降低耦合性。