访问者模式
由于它难理解、难实现。应用它会导致代码的可读性、可维护性变差,所以在开发中很少被用到。
定义
允许一个或者多个操作应用到一组对象上,解耦
操作
和对象本身
。
类图
实现
需求: 对PDF、Word格式进行处理,把里面的数据抽取到Txt文本文件中。
1. 定义访问者接口
/**
* 访问者接口
* 包含两个重载函数,分别处理两种不同类型的资源文件。具体选择哪个文件处理,需要在编译时进行绑定,
* 在各个Resource实现内部,会把this传递给当前方法,这样就可以知道绑定的对象是哪个,选用合适的重载方法进行处理。
* 具体做什么业务处理,由实现这个visitor接口的具体实现类来决定。
*
*/
public interface Visitor {
/**
* 定义PDF类型
* @param pdfResourceFile
*/
void visit(PdfResourceFile pdfResourceFile);
/**
* 定义Word类型
* @param wordResourceFile
*/
void visit(WordResourceFile wordResourceFile);
}
2. 定义Visitor实现类
/**
* 定义压缩功能访问者实现类
*
*/
public class CompressorVisitor implements Visitor{
/**
* PDF类型压缩
* @param pdfResourceFile
*/
@Override
public void visit(PdfResourceFile pdfResourceFile) {
System.out.println("compress pdf");
}
/**
* Word类型压缩
* @param wordResourceFile
*/
@Override
public void visit(WordResourceFile wordResourceFile) {
System.out.println("compress word");
}
}
/**
* 文件抽取实现类
*
*/
public class ExtractVisitor implements Visitor {
/**
* PDF文件抽取
* @param pdfResourceFile
*/
@Override
public void visit(PdfResourceFile pdfResourceFile) {
System.out.println("PDF EXTRACT.");
}
/**
* word文件抽取
* @param wordResourceFile
*/
@Override
public void visit(WordResourceFile wordResourceFile) {
System.out.println("WORD EXTRACT.");
}
}
3. 定义ResourceFile抽象类
/**
* 资源抽象类
*/
public abstract class ResourceFile {
protected String filePath;
public ResourceFile(String filePath) {
this.filePath = filePath;
}
/**
* 这里可以接收visitor的标准实现,具体功能由Visitor具体实现类决定。
* 可以接收CompressorVisitor用来压缩文件、ExtractVisitor用来抽取文件内容,将来还会有索引文件建立等功能需求,只需要实现visitor接口即可。
* 功能的实现
* @param visitor
*/
public abstract void accept(Visitor visitor);
}
4. 定义ResourceFile实现类
/**
* PDF资源实现类
*/
public class PdfResourceFile extends ResourceFile {
public PdfResourceFile(String filePath) {
super(filePath);
}
/**
* 这里可以接收visitor的标准实现,具体功能由Visitor具体实现类决定。
* @param visitor
*/
@Override
public void accept(Visitor visitor) {
// 重点。需要传入此时的对象,否则,visitor不晓得调用哪个重载方法
visitor.visit(this);
}
}
/**
* Word资源实现类
*/
public class WordResourceFile extends ResourceFile {
public WordResourceFile(String filePath) {
super(filePath);
}
/**
*
* @param visitor
*/
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
5. Main
/**
* 访问者模式(GoF):允许一个或者多个操作应用到一组对象上,解耦操作和对象本身
* 应用场景:一般来说,访问者模式针对的是一组类型不同的对象(PDF、Word...) ,虽然它们类型不同,但是拥有相同父类或实现相同接口。
* 在不同的场景下,我们需要对这组对象进行一系列不相关的业务操作,但为了避免不断添加功能导致类(PdfResourceFile、WordResourceFile)不断膨胀,职责越来越不单一
* 以及频繁地添加功能导致的频繁代码修改,我们使用访问者模式,将对象与操作解耦,将这些业务操作抽离出来,定义在独立的细分的访问者类(CompressorVisitor、ExtractVisitor)中
*/
public class M {
public static void main(String[] args) {
Visitor compress = new CompressorVisitor();
Visitor extractor = new ExtractVisitor();
List<ResourceFile> sourceFiles = listAllResourceFiles("h");
for (ResourceFile sourceFile : sourceFiles) {
sourceFile.accept(compress);
}
for (ResourceFile sourceFile : sourceFiles) {
sourceFile.accept(extractor);
}
}
private static List<ResourceFile> listAllResourceFiles(String resourcePath) {
ArrayList<ResourceFile> resourceFiles = new ArrayList<>();
resourceFiles.add(new PdfResourceFile("a.pdf"));
resourceFiles.add(new WordResourceFile("b.word"));
return resourceFiles;
}
}
扩展
/**
* 功能扩展一:建立索引文件
*/
public class IndexVisitor implements Visitor{
@Override
public void visit(PdfResourceFile pdfResourceFile) {
System.out.println("对PDF建立索引");
}
@Override
public void visit(WordResourceFile wordResourceFile) {
System.out.println("对Word建立索引");
}
}
// 索引文件
IndexVisitor indexVisitor = new IndexVisitor();
for (ResourceFile sourceFile : sourceFiles) {
sourceFile.accept(indexVisitor);
}
总结
- 一般来说,
访问者模式
针对的是一组
类型不同的对象。不过,尽管这组对象的类型是不同的,但是,它们继承相同的父类或者实现相同的接口。 访问者模式
允许一个或者多个操作应用到一组对象上,设计意图是解耦操作
和对象本身
,保持类职责单一
、满足开闭原则
以及降低代码的复杂性。- 对于
访问者模式
,学习的主要难点
在代码实现。而代码实现比较复杂的主要原因是,函数重载
在大部分面向对象编程语言中是静态绑定
的。也就是说,调用类的哪个重载函数,是在编译期间,由参数的声明类型决定的,而非运行时,根据参数的实际类型决定的。 - 正是因为代码实现难理解,所以,在项目中应用这种模式,会导致代码的可读性比较差。
Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。
它的内容包括:
- 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
- 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
- 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
- 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
- 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
- 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
- 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
- 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw
目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:
想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询
同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。