附链
你也可以在这些平台阅读本文:
定义
封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改,接受这个操作的数据结构可以保持不变。
访问者模式适用于数据结构相对稳定的系统,它把数据结构和作用于数据结构上的操作之间的耦合解脱开,使得操作集合可以相对自由的演化。
访问者模式的核心就是根据不同的访问者对相同的数据产生不同的操作行为。
五个角色
访问者模式主要包含以下五个角色:
- 抽象访问者类Visitor:为对象结构中的每一个具体元素类提供一个访问操作。
- 具体访问者类Concrete Visitor:实现抽象访问者中声明的各个方法。
- 抽象元素类Element:定义一个接受操作,以被接受的访问者对象作为其参数。
- 具体元素类Concrete Element:实现抽象元素类的接受操作。
- 对象结构类Object Structure:是一个包含元素角色的容器,能够遍历其内部的元素,同时提供一个高层的接口以允许访问者访问它的元素。
场景示例
笔者这里以用户访问笔者CSDN博客为例。
笔者这里将用户分为匿名用户(非注册用户)和CSDN用户(注册用户)两种,即不同的访问者。
博客在这里可以当做对象结构,而每篇博文可以是一个具体的元素。
创建抽象访问者类
按照要求为对象结构中的每一个具体的元素类提供一个访问操作。
/**
* @author zhh
* @description 抽象访问者
* @date 2020-03-03 17:07
*/
public interface Visitor {
/**
* 访问文章内容
* @param articleContent 文章内容
*/
void visit(ArticleContent articleContent);
/**
* 访问资源内容
* @param resourceContent 资源内容
*/
void visit(ResourceContent resourceContent);
}
创建具体访问者类
/**
* @author zhh
* @description 注册用户
* @date 2020-03-03 17:14
*/
public class RegisteredUserVisitor implements Visitor {
public void visit(ArticleContent articleContent) {
System.out.println(String.format("CSDN用户访问博客文章[%s]", articleContent.getName()));
}
public void visit(ResourceContent resourceContent) {
System.out.println(String.format("CSDN用户下载博客资源[%s]", resourceContent.getName()));
}
}
/**
* @author zhh
* @description 非注册用户
* @date 2020-03-03 17:06
*/
public class GuestUserVisitor implements Visitor {
public void visit(ArticleContent articleContent) {
System.out.println(String.format("匿名用户访问博客文章[%s]", articleContent.getName()));
}
public void visit(ResourceContent resourceContent) {
if (resourceContent.isNeedLogin()) {
System.out.println("匿名用户无法访问当前资源, 请登录!");
return;
}
System.out.println(String.format("匿名用户下载博客资源[%s]", resourceContent.getName()));
}
}
创建抽象元素类
/**
* @author zhh
* @description 内容类
* @date 2020-03-03 17:08
*/
public abstract class Content {
/**
* 名称
*/
private String name;
public Content(String name) {
this.name = name;
}
public String getName() {
return name;
}
/**
* 接受操作, 核心方法, 接受访问者访问
* @param visitor 访问者
*/
public abstract void accept(Visitior visitor);
}
创建具体元素类
/**
* @author zhh
* @description 文章内容
* @date 2020-03-03 17:11
*/
public class ArticleContent extends Content {
public ArticleContent(String name) {
super(name);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
/**
* @author zhh
* @description 资源内容
* @date 2020-03-03 17:15
*/
public class ResourceContent extends Content {
/**
* 是否需要登录
*/
private boolean needLogin;
public ResourceContent(String name, boolean needLogin) {
super(name);
this.needLogin = needLogin;
}
public boolean isNeedLogin() {
return needLogin;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
创建对象结构类
/**
* @author zhh
* @description 博客类
* @date 2020-03-03 17:34
*/
public class Blog {
private List<Content> contentList = new ArrayList<Content>();
/**
* 添加内容
* @param content 内容
*/
public void addContent(Content content) {
contentList.add(content);
}
/**
* 删除内容
* @param content 内容
*/
public void removeContent(Content content) {
contentList.remove(content);
}
/**
* 接受访问者访问
* @param visitor 访问者
*/
public void accept(Visitor visitor) {
for (Content content : contentList) {
content.accept(visitor);
}
}
}
测试类及输出
/**
* @author zhh
* @description 测试类
* @date 2020-03-03 17:34
*/
public class Test {
public static void main(String[] args) {
// 创建对象结构
Blog blog = new Blog();
// 创建具体元素
Content articleContent = new ArticleContent("Java设计模式之行为型-访问者模式 (Visitor)");
Content resourceContent = new ResourceContent("代码生成器工具.zip", true);
blog.addContent(articleContent);
blog.addContent(resourceContent);
// 创建不同访问对象
Visitor registeredUserVisitor = new RegisteredUserVisitor();
Visitor guestUserVisitor = new GuestUserVisitor();
// 不同对象分别访问数据
blog.accept(registeredUserVisitor);
blog.accept(guestUserVisitor);
}
}
测试类的输出结果如下:
CSDN用户访问博客文章[Java设计模式之行为型-访问者模式 (Visitor)]
CSDN用户下载博客资源[代码生成器工具.zip]
匿名用户访问博客文章[Java设计模式之行为型-访问者模式 (Visitor)]
匿名用户无法访问当前资源, 请登录!
类结构图
以上示例类的结构图如下所示
总结
适用场景
对象的数据结构相对稳定,但是其操作算法经常发生变化的程序。
优点
良好的扩展性。能够在不修改对象结构中的元素情况下,为对象结构中的元素添加新功能,也就是增加新的访问者类。
缺点
- 增加新的数据结构较为困难,具体的元素的变更也较为麻烦。
- 破坏了封装性。访问者模式中的具体元素会暴露给访问者。
参考
- 《Head First 设计模式》
- 《大话设计模式》
- 维基百科-访问者模式
- 菜鸟教程-访问者模式