Java描述设计模式(23):访问者模式
本文源码:GitHub·点这里 || GitEE·点这里
一、生活场景
1、场景描述
电竞是游戏比赛达到“竞技”层面的体育项目。利用电子设备作为运动器械进行的、人与人之间的智力对抗运动。通过电竞,可以提高人的反应能力、协调能力、团队精神等。但是不同人群的对电竞的持有的观念不一样,有的人认为电竞就是沉迷网络,持反对态度,而有的人就比较赞同。下面基于访问者模式来描述该场景。
2、场景图解

3、代码实现
public class C01_InScene {
public static void main(String[] args) {
DataSet dataSet = new DataSet() ;
dataSet.addCrowd(new Youth());
dataSet.addCrowd(new MiddleAge());
CrowdView crowdView = new Against() ;
dataSet.display(crowdView);
crowdView = new Approve() ;
dataSet.display(crowdView);
}
}
/**
* 双分派,不同人群管理
*/
abstract class Crowd {
abstract void accept(CrowdView action);
}
class Youth extends Crowd {
@Override
public void accept(CrowdView view) {
view.getYouthView(this);
}
}
class MiddleAge extends Crowd {
@Override
public void accept(CrowdView view) {
view.getMiddleAgeView (this);
}
}
/**
* 不同人群观念的管理
*/
abstract class CrowdView {
// 青年人观念
abstract void getYouthView (Youth youth);
// 中年人观念
abstract void getMiddleAgeView (MiddleAge middleAge);
}
class Approve extends CrowdView {
@Override
public void getYouthView(Youth youth) {
System.out.println("青年人赞同电竞");
}
@Override
public void getMiddleAgeView(MiddleAge middleAge) {
System.out.println("中年人赞同电竞");
}
}
class Against extends CrowdView {
@Override
public void getYouthView(Youth youth) {
System.out.println("青年人反对电竞");
}
@Override
public void getMiddleAgeView(MiddleAge middleAge) {
System.out.println("中年人反对电竞");
}
}
/**
* 提供一个数据集合
*/
class DataSet {
private List<Crowd> crowdList = new ArrayList<>();
public void addCrowd (Crowd crowd) {
crowdList.add(crowd);
}
public void display(CrowdView crowdView) {
for(Crowd crowd : crowdList) {
crowd.accept(crowdView);
}
}
}
二、访问者模式
1、基础概念
访问者模式是对象的行为模式,把作用于数据结构的各元素的操作封装,操作之间没有关联。可以在不改变数据结构的前提下定义作用于这些元素的不同的操作。主要将数据结构与数据操作分离,解决数据结构和操作耦合问题核心原理:被访问的类里面加对外提供接待访问者的接口。
2、模式图解

3、核心角色
- 抽象访问者角色
声明多个方法操作,具体访问者角色需要实现的接口。
- 具体访问者角色
实现抽象访问者所声明的接口,就是各个访问操作。
- 抽象节点角色
声明接受操作,接受访问者对象作为参数。
- 具体节点角色
实现抽象节点所规定的具体操作。
- 结构对象角色
能枚举结构中的所有元素,可以提供一个高层的接口,用来允许访问者对象访问每一个元素。
4、源码实现
public class C02_Visitor {
public static void main(String[] args) {
ObjectStructure obs = new ObjectStructure();
obs.add(new NodeA());
obs.add(new NodeB());
Visitor visitor = new VisitorA();
obs.doAccept(visitor);
}
}
/**
* 抽象访问者角色
*/
interface Visitor {
/**
* NodeA的访问操作
*/
void visit(NodeA node);
/**
* NodeB的访问操作
*/
void visit(NodeB node);
}
/**
* 具体访问者角色
*/
class VisitorA implements Visitor {
@Override
public void visit(NodeA node) {
node.operationA() ;
}
@Override
public void visit(NodeB node) {
node.operationB() ;
}
}
class VisitorB implements Visitor {
@Override
public void visit(NodeA node) {
node.operationA() ;
}
@Override
public void visit(NodeB node) {
node.operationB() ;
}
}
/**
* 抽象节点角色
*/
abstract class Node {
/**
* 接收访问者
*/
abstract void accept(Visitor visitor);
}
/**
* 具体节点角色
*/
class NodeA extends Node{
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public void operationA(){
System.out.println("NodeA.operationA");
}
}
class NodeB extends Node{
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public void operationB(){
System.out.println("NodeB.operationB");
}
}
/**
* 结构对象角色类
*/
class ObjectStructure {
private List<Node> nodes = new ArrayList<>();
public void detach(Node node) {
nodes.remove(node);
}
public void add(Node node){
nodes.add(node);
}
public void doAccept(Visitor visitor){
for(Node node : nodes) {
node.accept(visitor);
}
}
}
三、Spring框架应用
1、Bean结构的访问
BeanDefinitionVisitor类,遍历bean的各个属性;接口 BeanDefinition,定义Bean的各样信息,比如属性值、构造方法、参数等等。这里封装操作bean结构的相关方法,但却没有改变bean的结构。
2、核心代码块
public class BeanDefinitionVisitor {
public void visitBeanDefinition(BeanDefinition beanDefinition) {
this.visitParentName(beanDefinition);
this.visitBeanClassName(beanDefinition);
this.visitFactoryBeanName(beanDefinition);
this.visitFactoryMethodName(beanDefinition);
this.visitScope(beanDefinition);
if (beanDefinition.hasPropertyValues()) {
this.visitPropertyValues(beanDefinition.getPropertyValues());
}
if (beanDefinition.hasConstructorArgumentValues()) {
ConstructorArgumentValues cas = beanDefinition.getConstructorArgumentValues();
this.visitIndexedArgumentValues(cas.getIndexedArgumentValues());
this.visitGenericArgumentValues(cas.getGenericArgumentValues());
}
}
}
四、模式总结
1、优点描述
(1) 访问者模式符合单一职责原则、使程序具有良好的扩展性、灵活性;
(2) 访问者模式适用与拦截器与过滤器等常见功能,数据结构相对稳定的场景;
2、缺点描述
(1) 访问者关注其他类的内部细节,依赖性强,违反迪米特法则,这样导致具体元素更新麻烦;
(2) 访问者依赖具体元素,不是抽象元素,面向细节编程,违背依赖倒转原则;
五、源代码地址
GitHub·地址
https://github.com/cicadasmile/model-arithmetic-parent
GitEE·地址
https://gitee.com/cicadasmile/model-arithmetic-parent

Java描述设计模式(23):访问者模式的更多相关文章
- [设计模式] 23 访问者模式 visitor Pattern
在GOF的<设计模式:可复用面向对象软件的基础>一书中对访问者模式是这样说的:表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作.访问 ...
- 折腾Java设计模式之访问者模式
博客原文地址:折腾Java设计模式之访问者模式 访问者模式 Represent an operation to be performed on the elements of an object st ...
- C#设计模式总结 C#设计模式(22)——访问者模式(Vistor Pattern) C#设计模式总结 .NET Core launch.json 简介 利用Bootstrap Paginator插件和knockout.js完成分页功能 图片在线裁剪和图片上传总结 循序渐进学.Net Core Web Api开发系列【2】:利用Swagger调试WebApi
C#设计模式总结 一. 设计原则 使用设计模式的根本原因是适应变化,提高代码复用率,使软件更具有可维护性和可扩展性.并且,在进行设计的时候,也需要遵循以下几个原则:单一职责原则.开放封闭原则.里氏代替 ...
- C#设计模式(22)——访问者模式(Vistor Pattern)
一.引言 在上一篇博文中分享了责任链模式,责任链模式主要应用在系统中的某些功能需要多个对象参与才能完成的场景.在这篇博文中,我将为大家分享我对访问者模式的理解. 二.访问者模式介绍 2.1 访问者模式 ...
- 乐在其中设计模式(C#) - 访问者模式(Visitor Pattern)
原文:乐在其中设计模式(C#) - 访问者模式(Visitor Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 访问者模式(Visitor Pattern) 作者:webabc ...
- 北风设计模式课程---访问者模式(Visitor)
北风设计模式课程---访问者模式(Visitor) 一.总结 一句话总结: 设计模式是日常问题的经验总结方案,所以学好设计模式对日常出现的问题可以有很好的解决. 访问者设计模式有点神似 抽象工厂模式, ...
- JAVA设计模式之访问者模式
在阎宏博士的<JAVA与模式>一书中开头是这样描述访问者(Visitor)模式的: 访问者模式是对象的行为模式.访问者模式的目的是封装一些施加于某种数据结构元素之上的操作.一旦这些操作需要 ...
- 15.java设计模式之访问者模式
基本需求: 电脑需要键盘鼠标等固定的组件组成 现在分为个人,组织等去买电脑,而同一种组件对不同的人(访问者)做出不同的折扣,从而电脑的价格也不一样 传统的解决方法:在组件内部进行判断访问人的类型,从而 ...
- 23种设计模式之访问者模式(Visitor)
访问者模式是一种对象的行为性模式,用于表示一个作用于某对象结构中的各元素的操作,它使得用户可以再不改变各元素的类的前提下定义作用于这些元素的新操作.访问者模式使得增加新的操作变得很容易,但在一定程度上 ...
随机推荐
- Yii2.0教程应用结构篇 —— 入口脚本
入口脚本是应用启动流程中的第一环,一个应用(不管是网页应用还是控制台应用)只有一个入口脚本.终端用户的请求通过入口脚本实例化应用并将将请求转发到应用. Web 应用的入口脚本必须放在终端用户能够访问的 ...
- 使用Jersey构建图片服务器
使用Jersey构建图片服务器 前台页面代码 <form id="jvForm" action="add.do" method="post&qu ...
- 三、DockerFile 定制属于自己的专属镜像
前言 上篇文章我们知道了怎么操作镜像和容器,到基础都是从已经存在的镜像开始的,那我们自己怎样搭建一个镜像并使用它呢?接下来就让我们学习使用dockerfile 创建属于自己的镜像吧. dockerfi ...
- The usage of Markdown---标题
更新时间:2019.09.14 目录: 1. 序言 2. 标题 2.1 类Atx形式 2.2 类Setext形式 3. 总结 1. 序言 Markdown是一种纯文本的标记语言,只要熟悉M ...
- Redis(十四)Redis 在Java Web 中的应用
在传统的 Java Web 项目中,使用数据库进行存储数据,但是有一些致命的弊端,这些弊端主要来自于性能方面. 由于数据库持久化数据主要是面向磁盘,而磁盘的读/写比较慢,在一般管理系统中,由于不存在高 ...
- 基于jquery,php实现AJAX长轮询(LongPoll),类似推送机制
HTTP是无状态.单向的协议,用户只能够通过客服端向服务器发送请求并由服务器处理发回一个响应.若要实现聊天室.WEBQQ.在线客服.邮箱等这些即时通讯的应用,就要用到“ 服务器推送技术(Comet)” ...
- jwt token
1 ,session 认证机制: ,用户登录,传递用户名和密码给客户端 ,服务器进行用户名和密码的校验,如果校验成功,将用户保存到session ,将sessionid通过cookie返回给客服端,客 ...
- Java自动化测试框架-07 - TestNG之Factory篇 - 欢快畅游梦幻工厂(详细教程)
简介 最近忙着装修博客园,没时间更新文章,今天终于抽出时间把上次写的一半的文章给写完了,新的博客园风格,希望大家喜欢.今天继续介绍testng的相关知识--工厂. 工厂允许你动态的创建测试.例如,假设 ...
- ArcGIS Engine空间分析之拓扑分析的实现
简单介绍: 拓扑学是一门研究几何图形位置关系的科学. GIS所关注的拓扑主要集中在拓扑关系——存在于地理实体间的拓扑关系. 拓扑关系在GIS中起着描述两个地理实体的相对空间位置的重要作用.它是GIS空 ...
- 第二十六章 system v消息队列(二)
msgsnd int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); 作用: 把一条消息添加到消息队列中 参数: msqi ...