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