访问者模式

news2024/11/29 20:38:45

一、访问者模式

1、定义

访问者模式(Visitor Pattern)是一种将数据结构与数据操作分离的设计模式,指封装一些作用于某种数据结构中的各元素的操作,可以在不改变数据结构的前提下定义作用于这些元素的新的操作,属于行为型设计模式。

访问者模式的基本思想是,针对系统中拥有固定类型数的对象结构(元素),在其内提供一个 accept()方法来接受访问者对象的访问。不同的访问者对同一个元素的访问内容是不同,使得相同的元素集合可以产生不同的数据结果。

访问者模式又被称为最复杂的设计模式,使用频率不到。因为在开发中,我们很难找到数据结构不变化的情况。

访问者模式的核心是解耦数据结构与数据操作,使得对元素的操作具备优秀的扩展性。

2、结构

(1)模式的结构

主要角色如下:

  • 抽象访问者(IVisitor):接口或者抽象类,该类定义了一个 visit()方法用于访问每一个具体的元素,其参数就是具体元素对象。
  • 具体访问者(ConcreteVisitor):实现对具体元素的操作。
  • 抽象元素(IElement):接口或者抽象类,该类定义了一个接受访问者访问的方法 accept()方法,表示所有元素类型都支持被访问者访问。
  • 具体元素(ConcreteElement):具体元素类型,提供接受访问者的具体实现。通常的实现都为 visitor.visit(this)。
  • 结构对象(ObjectStructure):该类内部维护了元素集合,并提供方法接受访问者对该集合所有元素进行操作。

3、优缺点

优点:

  • 解耦了数据结构与数据操作,使得操作集合可以独立变化。
  • 可以通过扩展访问者角色,实现对数据集的不同操作,程序扩展性更好。
  • 元素具体类型并非单一,访问者均可操作。
  • 各角色职责分离,符合单一职责原则。

缺点:

  • 无法增加元素类型,会违背开闭原则。
  • 具体元素变更困难,修改的范围很大。
  • 违背依赖倒置原则:访问者角色依赖的是具体元素类型,而不是抽象。

4、使用场景

  • 数据结构稳定,作用于数据结构的操作经常变化的场景。
  • 需要数据结构与数据操作分离的场景。
  • 需要对不同数据类型(元素)进行操作,而不使用分支判断具体类型的场景

5、在框架源码中使用

  • Java的 NIO模块下的 FileVisitor接口。
  • Spring IoC中的 BeanDefinitionVisitor类。

二、模式的通用实现

代码如下:

public class VisitorPattern {

    public static void main(String[] args) {
        ObjectStructure objectStructure = new ObjectStructure();

        IVisitor visitorA = new ConcreteVisitorA();
        objectStructure.showAccept(visitorA);

        System.out.println("====================");
        IVisitor visitorB = new ConcreteVisitorB();
        objectStructure.showAccept(visitorB);
    }
}

// 抽象访问者
interface IVisitor{
    void visit(ConcreteElementA element);

    void visit(ConcreteElementB element);
}

// 具体访问者
class ConcreteVisitorA implements IVisitor{
    @Override
    public void visit(ConcreteElementA element) {
        String result = element.operationA();
        System.out.println("ConcreteVisitorA handler -> result from " + element.getClass().getSimpleName() +", result = " + result);
    }

    @Override
    public void visit(ConcreteElementB element) {
        int result = element.operationB();
        System.out.println("ConcreteVisitorA handler -> result from " + element.getClass().getSimpleName() +", result = " + result);
    }
}

class ConcreteVisitorB implements IVisitor{
    @Override
    public void visit(ConcreteElementA element) {
        String result = element.operationA();
        System.out.println("ConcreteVisitorB handler -> result from " + element.getClass().getSimpleName() +", result = " + result);
    }

    @Override
    public void visit(ConcreteElementB element) {
        int result = element.operationB();
        System.out.println("ConcreteVisitorB handler -> result from " + element.getClass().getSimpleName() +", result = " + result);
    }
}

// 抽象元素
interface IElement{
    void accept(IVisitor visitor);
}

// 具体元素
class ConcreteElementA implements IElement{

    @Override
    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }

    public String operationA(){
        return this.getClass().getSimpleName();
    }
}

class ConcreteElementB implements IElement{

    @Override
    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }

    public int operationB(){
        return new Random().nextInt(100);
    }
}

// 结构对象
class ObjectStructure{
    private List<IElement> list = new ArrayList<>();

    {
        list.add(new ConcreteElementA());
        list.add(new ConcreteElementB());
    }

    // 遍历
    public void showAccept(IVisitor visitor){
        for (IElement element : this.list) {
            element.accept(visitor);
        }
    }
}

在这里插入图片描述

三、模式的应用实例

以 KPI考核的场景为例,领导查看员工的 KPI考核。

(1)员工基类 - 抽象元素

public abstract class Employee {

    protected String name;
    //员工 kpi数量
    protected int kpiCount;

    public Employee(String name) {
        this.name = name;
        this.kpiCount = new Random().nextInt(10);
    }

    public abstract void accept(IVisitor visitor);
}

(2)具体元素

public class Manager extends Employee {

	public Manager(String name) {
		super(name);
	}

	@Override
	public void accept(IVisitor visitor) {
		visitor.visit(this);
	}

	// 经理一年的产品量
	public int getProducts() {
		return new Random().nextInt(10);
	}
}

public class Engineer extends Employee{

    public Engineer(String name) {
        super(name);
    }

    @Override
    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }

    //工程师一年的代码量
    public int getCodeLines(){
        return new Random().nextInt(10 * 10000);
    }
}

(3)抽象访问者

public interface IVisitor {

    //访问工程师类型
    void visit(Engineer engineer);

    //访问经理类型
    void visit(Manager manager);
}

(4)具体访问者

// CEO访问者
public class CEOVisitor implements IVisitor{

    @Override
    public void visit(Engineer engineer) {
        System.out.println("工程师:" + engineer.name + ",KPI: " + engineer.kpiCount);
    }

    @Override
    public void visit(Manager manager) {
        System.out.println("经理:" + manager.name + ",KPI: " + manager.kpiCount + ",产品数量:" + manager.getProducts());
    }
}

// CTO访问者
public class CTOVisitor implements IVisitor{

    @Override
    public void visit(Engineer engineer) {
        System.out.println("工程师:" + engineer.name + ",代码行数: " + engineer.getCodeLines());
    }

    @Override
    public void visit(Manager manager) {
        System.out.println("经理:" + manager.name + ",产品数量: " + manager.getProducts());
    }
}

(5)业务报表类 - 结构对象

public class BusinessReport {
    private List<Employee> employeeList = new ArrayList<>();

    {
        employeeList.add(new Manager("经理A"));
        employeeList.add(new Engineer("Java工程师 - 赵云"));
        employeeList.add(new Engineer("Java工程师 - 后裔"));
        employeeList.add(new Manager("经理B"));
        employeeList.add(new Engineer("Java工程师 - 妲己"));
        employeeList.add(new Engineer("Java工程师 - 露娜"));
    }

    //遍历
    public void showReport(IVisitor visitor){
        for (Employee employee : this.employeeList) {
            employee.accept(visitor);
        }
    }
}

(6)测试

    public static void main(String[] args) {
        BusinessReport businessReport = new BusinessReport();

        System.out.println("=========CEO 看报表==============");
        businessReport.showReport(new CEOVisitor());

        System.out.println("=========CTO 看报表==============");
        businessReport.showReport(new CTOVisitor());
    }

在这里插入图片描述

– 求知若饥,虚心若愚。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/87780.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

漫画 | 这个北欧小国发明的编程技术,竟然占领全世界了!

上世纪60年代 &#xff0c;挪威计算中心。一个新来员工刚上班&#xff0c;发现有两个人居然在一楼的黑板前打架新员工立刻跑到电话接线员那里报告什么样的编程语言&#xff0c;能让两人大动肝火&#xff1f;当时Nygaard正在编写复杂系统的模拟程序&#xff0c;模拟程序要求先定…

【猿如意】中的『XMind』工具详情介绍

目录 一、工具名称 二、下载安装渠道 2.1 什么是猿如意&#xff1f; 2.2 如何下载猿如意&#xff1f; 2.3 如何在猿如意中下载开发工具&#xff1f; 三、XMind工具功能简介 四、XMind的下载和安装 4.1下载 4.2安装 五、XMind的基本使用 5.1新建项目 5.2系统模板的使…

【java】程序员基础能力测试33问,持续整理中

Java基础&#xff1a; 1&#xff1a;八大基本数据类型&#xff0c;及所占字节数&#xff1f; 2&#xff1a;讲下对面向对象的理解&#xff1f; 特征:封装、继承、多态; 基础:抽象 面向对象&#xff0c;主要就是将现实中的对象抽象成一个类&#xff0c;这个对象具有一定的属性…

[附源码]Python计算机毕业设计服装商城平台Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

项目管理之Git---submodule

0. 简介 在面对复杂系统时&#xff0c;所有的模块不可能同时开发在一个project下的&#xff0c;而更多的可能就是每个人开发不同的模块&#xff0c;并通过一个模块将这些模块都整合到一起&#xff0c;这时候submodule的作用就非常明显了。通过设置submodule可以轻易地对不同的…

通信基站安装步骤

基站设备安装步骤(移动通信基站施工过程),并说明施工要点和注意事项。 安装机柜流程。安装电源线和系统接地。 安装电源机柜时应直流配电柜接出-48V直流电源至RNC810机柜和NodeB机柜顶端配线盒。 将保护地线接至机柜接地螺栓上并紧固螺栓。 天馈系统安装。 天馈系统安装前的…

大数据学习:压缩与打包

文章目录任务一&#xff1a;压缩文件任务二&#xff1a;解压文件任务三&#xff1a;生成打包文件任务四&#xff1a;将打包文件解压到当前文件任务五&#xff1a;将打包的文件解压缩到指定目录任务六&#xff1a;解压打包文件里的某个目录任务一&#xff1a;压缩文件 在/tmp目…

redis地理位置和MongoDB地理索引的使用

比较 经度纬度都要在有效区间。经度范围介于 -180 到 180&#xff0c;纬度范围大致介于-90和到90。redis使用Zset结构存储&#xff0c;将经度值、纬度值转换为一个值&#xff0c;二维量变成一维量找附近的位置&#xff0c;效率极高&#xff0c;不过限于平面&#xff0c;且无法…

测量学:水准和导线测量实验报告+详细解析

目录 00 说明 实验1 闭合导线测量 实习目的 实习任务和内容 控制点的布置和测量技术要求&#xff08;绘制导线略图&#xff09; 导线略图 外业测量数据和记录相关表格&#xff08;附原始观测记录&#xff09; 原始观测数据记录如下&#xff1a; 记录表格如下&#xff…

Web3中文|星巴克拥抱Web3,新项目Odyssey开启数字旅程

12月8日&#xff0c;成立用于1971年&#xff0c;全球82个市场拥有超过32,000家门店的美国咖啡公司星巴克对其备受期待的Odyssey体验进行了测试&#xff0c;该体验将客户忠诚度奖励与NFT以及其他游戏元素相结合。 早在9月12日&#xff0c;星巴克宣布将推出Web3平台“Starbucks …

openEuler社区开源项目:CPDS(容器故障检测系统)介绍

容器故障检测系统 CPDS (Container Problem Detect System) 是由北京凝思软件股份有限公司&#xff08;以下简称“凝思软件”&#xff09;设计并开发的容器集群故障检测系统&#xff0c;该软件系统实现了对容器TOP故障、亚健康状态的监测与识别。 2022年11月&#xff0c;凝思软…

isp,iap,sw-jtag

https://blog.csdn.net/weixin_45905650/article/details/107707858?ops_request_misc%257B%2522request%255Fid%2522%253A%2522167098526816800180634199%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id167098526816800180634199&biz_i…

JS:通过setTimeout和promise来了解js代码执行机制(面试题讲解)

目录 1.setTimeout定时器 2.promise函数 补充&#xff1a;1.什么是宏任务与微任务 补充&#xff1a;2.宏任务和微任务的执行顺序 补充&#xff1a;3.js的执行顺序 补充&#xff1a;4.答案揭晓 前几天碰到一个关于js执行顺序的面试题&#xff0c;一时间竟然有点模糊&#…

BCN-PEG-Folate 环丙烷环辛炔聚乙二醇叶酸 BCN-PEG-FA

双环[6,1,0]壬炔 (BCN) &#xff08;环丙烷环辛炔&#xff09;可以通过无铜的点击化学与叠氮化物标记的分子或生物分子反应生成稳定的三氮唑连接。 产品名称 BCN-PEG-Folate 环丙烷环辛炔聚乙二醇叶酸 中文名称 环丙烷环辛炔聚乙二醇叶酸 英文名称 BCN-PEG-Folate BCN…

统信软件高级系统研发工程师:sysOM 在系统可靠性与安全上实践

一、系统可靠性 SRE是判断系统是否可靠、可用、有效重要标准&#xff0c;它包括&#xff1a; 服务水平指标SLI&#xff1a;衡量服务使用情况量化指标。 比如IO读写速率、网络延迟。通常量化指标会转换为比率、平均值或百分比。服务水平目标SLO&#xff1a;一段时间、区间内的目…

花1块钱让你的网站支持 ChatGPT

点击上方卡片“前端司南”关注我您的关注意义重大原创前端司南最近 ChatGPT 在技术圈子可太火了&#xff0c;票圈也被刷屏。我也决定来凑个热闹&#xff0c;给自己的博客加一个 ChatGPT 对话功能。先附上体验链接[1]&#xff0c;源码在底部也可以找到。体验 ChatGPTChatGPT[2] …

1区SCI潜力刊,中科院分区即将更新,有望冲击2区

1区 计算机物联网类SCI&EI 01 期刊详情 【出版社】Elsevier 【指标情况】自引率6.30% 【期刊简介】IF:5.5-6.0&#xff0c;JCR1区&#xff0c;中科院分区预计月底公布 【检索情况】SCI&EI 双检&#xff0c;正刊 【参考周期】3-4个月左右录用 【截稿日期】2023.2.…

cv2.circle()函数报错(tensor 转 array 感觉是bug)

前言 我不理解为啥opencv-python可视化一堆报错&#xff0c;同一个三通道图像&#xff0c;cv2.imshow()没有问题&#xff0c;cv2.circle()就一直有问题&#xff0c;搞了一晚&#xff0c;心态炸了&#xff01;&#xff01;&#xff01; cv2需要的图片矩阵&#xff08;H, W, C&…

FKM规范 针对非焊接构件疲劳强度评估的实例介绍(下篇)

本文主要结合FKM规范及FKM inside ANSYS软件针对非焊接构件的手动计算实例及软件计算实例进行介绍&#xff0c;希望大家对FKM规范在非焊接构件疲劳强度评估中的手动及软件计算过程有基本的了解。 一、写在前面 FKM Inside ANSYS软件&#xff0c;该软件是在FKM 规范的基础上&a…

不想写日报、周报,这个报表自动化软件太牛了,仅需三分钟

昨天看到一个哥们发帖说IT部门负责做报表的同事阳了&#xff0c;再加上年底各个业务部门报表需求旺盛&#xff0c;现在他们是忙的饭都吃不上&#xff0c;天天凌晨才能回家。京东的人倒是被解放了&#xff0c;毕竟强东说汇报只能1页ppt。但对于万千其他公司的朋友们来说&#xf…