一、概述
访问者模式(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学习资料
[工作文件夹]下,已找到 旅游项目文件
四、常见应用场景
- 对象结构相对稳定,但其操作算法经常变化的程序。
- 对象结构中的对象需要提供多种不同且不相关的操作,而且要避免让这些操作的变化影响对象的结构。