访问者模式(Visitor Pattern)

访问者模式

说明

访问者模式(Visitor Pattern)属于行为型模式,表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
该模式是将数据结构与数据操作分离的设计模式,是将作用于某种数据结构中的各元素的操作封装起来。该模式的实施前提是数据结构相对稳定,不会频繁变动,但是作用于结构上的操作又经常变动。

结构

访问者模式的主要角色如下:
抽象访问者(Visitor):即作用于元素操作的抽象,定义了访问具体元素的接口;
具体访问者(Concrete Visitor):根据需求实现对具体元素的操作;
抽象元素(Element):被访问的元素抽象,定义了接收访问者的接口;
具体元素(Concrete Element):被访问的具体元素,实现接收方法;
结构对象(Object Struture):维护了具体元素的集合,并提供方法接收访问者对集合中的元素进行访问。
访问者模式-类结构图

代码案例

业务背景是:某个培训机构只有语文、英语、数学老师,每个科目的老师都有对应的行为,并且行为会随着需求而改变。

反例

/**
 * @program: visitor
 * @description: 老师抽象类
 * @author: wxw
 * @create: 2024-03-14 16:12
 **/
public abstract class Teacher {

    // 姓名
    protected String name;

    public Teacher(String name) {
        this.name = name;
    }

    // 备课
    public abstract void prepareLessons();

    // 上课
    public abstract void giveClass();

    // 布置作业
    public abstract void assignHomework();

    // 批改作业
    public abstract void homeworkCorrecting();
}
/**
 * @program: visitor
 * @description: 语文老师
 * @author: wxw
 * @create: 2024-03-14 16:15
 **/
public class ChineseTeacher extends Teacher{

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

    @Override
    public void prepareLessons() {
        System.out.println(String.format("语文老师【%s】开始备课.", this.name));
    }

    @Override
    public void giveClass() {
        System.out.println(String.format("语文老师【%s】开始授课.", this.name));
    }

    @Override
    public void assignHomework() {
        System.out.println(String.format("语文老师【%s】开始布置作业.", this.name));
    }

    @Override
    public void homeworkCorrecting() {
        System.out.println(String.format("语文老师【%s】开始批改作业.", this.name));
    }

}
/**
 * @program: visitor
 * @description: 英语老师
 * @author: wxw
 * @create: 2024-03-14 16:15
 **/
public class EnglishTeacher extends Teacher{

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

    @Override
    public void prepareLessons() {
        System.out.println(String.format("英语老师【%s】开始备课.", this.name));
    }

    @Override
    public void giveClass() {
        System.out.println(String.format("英语老师【%s】开始授课.", this.name));
    }

    @Override
    public void assignHomework() {
        System.out.println(String.format("英语老师【%s】开始布置作业.", this.name));
    }

    @Override
    public void homeworkCorrecting() {
        System.out.println(String.format("英语老师【%s】开始批改作业.", this.name));
    }

}
/**
 * @program: visitor
 * @description: 数学老师
 * @author: wxw
 * @create: 2024-03-14 16:15
 **/
public class MathTeacher extends Teacher{

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

    @Override
    public void prepareLessons() {
        System.out.println(String.format("数学老师【%s】开始备课.", this.name));
    }

    @Override
    public void giveClass() {
        System.out.println(String.format("数学老师【%s】开始授课.", this.name));
    }

    @Override
    public void assignHomework() {
        System.out.println(String.format("数学老师【%s】开始布置作业.", this.name));
    }

    @Override
    public void homeworkCorrecting() {
        System.out.println(String.format("数学老师【%s】开始批改作业.", this.name));
    }

}
public class Test {
    public static void main(String[] args) {
        List<Teacher> teachers = new ArrayList<>();
        Teacher zhangsan = new ChineseTeacher("张三");
        Teacher lisi = new MathTeacher("李四");
        Teacher wangwu = new EnglishTeacher("王五");
        teachers.add(zhangsan);
        teachers.add(lisi);
        teachers.add(wangwu);

        for (Teacher t: teachers) {
            System.out.println("============================");
            t.prepareLessons();
            t.giveClass();
            t.assignHomework();
            t.homeworkCorrecting();
            System.out.println("============================");
        }
    }
}

假设培训机构为了提高教学质量,要求所有老师都必须跟同学进行单独沟通,了解每个同学的情况。
这时就需要在Teacher抽象类中添加沟通的方法,所有的子类都得实现该方法,违背了开闭原则。

重构后

抽象元素(Element)

/**
 * @program: visitor
 * @description: 老师抽象类
 *              抽象元素(Element)
 * @author: wxw
 * @create: 2024-03-14 16:12
 **/
public abstract class Teacher {

    // 姓名
    protected String name;

    public Teacher(String name) {
        this.name = name;
    }

    // 接收方法
    public abstract void accept(IActionVisitor actionVisitor);
}

抽象访问者(Visitor)

/**
 * @program: visitor
 * @description: 老师行为访问者接口
 *              抽象访问者(Visitor)
 * @author: wxw
 * @create: 2024-03-14 16:33
 **/
public interface IActionVisitor {

    // 访问语文老师
    void visitorChineseTeacher(ChineseTeacher chineseTeacher);
    // 访问英语老师
    void visitorEnglishTeacher(EnglishTeacher englishTeacher);
    // 访问数学老师
    void visitorMathTeacher(MathTeacher mathTeacher);

}

具体元素(Concrete Element)

/**
 * @program: visitor
 * @description: 语文老师
 *              具体元素(Concrete Element)
 * @author: wxw
 * @create: 2024-03-14 16:15
 **/
public class ChineseTeacher extends Teacher {

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

    @Override
    public void accept(IActionVisitor actionVisitor) {
        actionVisitor.visitorChineseTeacher(this);
    }

}

/**
 * @program: visitor
 * @description: 英语老师
 *              具体元素(Concrete Element)
 * @author: wxw
 * @create: 2024-03-14 16:15
 **/
public class EnglishTeacher extends Teacher {

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

    @Override
    public void accept(IActionVisitor actionVisitor) {
        actionVisitor.visitorEnglishTeacher(this);
    }

}

/**
 * @program: visitor
 * @description: 数学老师
 *              具体元素(Concrete Element)
 * @author: wxw
 * @create: 2024-03-14 16:15
 **/
public class MathTeacher extends Teacher {

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

    @Override
    public void accept(IActionVisitor actionVisitor) {
        actionVisitor.visitorMathTeacher(this);
    }
}

具体访问者(Concrete Visitor)

/**
 * @program: visitor
 * @description: 备课访问者
 *              具体访问者(Concrete Visitor)
 * @author: wxw
 * @create: 2024-03-14 16:37
 **/
public class PrepareLessonsVisitor implements IActionVisitor {
    @Override
    public void visitorChineseTeacher(ChineseTeacher chineseTeacher) {
        System.out.println(String.format("语文老师【%s】开始备课.", chineseTeacher.name));
    }

    @Override
    public void visitorEnglishTeacher(EnglishTeacher englishTeacher) {
        System.out.println(String.format("英语老师【%s】开始备课.", englishTeacher.name));
    }

    @Override
    public void visitorMathTeacher(MathTeacher mathTeacher) {
        System.out.println(String.format("数学老师【%s】开始备课.", mathTeacher.name));
    }
}

/**
 * @program: visitor
 * @description: 上课访问者
 *              具体访问者(Concrete Visitor)
 * @author: wxw
 * @create: 2024-03-14 16:37
 **/
public class GiveClassVisitor implements IActionVisitor {
    @Override
    public void visitorChineseTeacher(ChineseTeacher chineseTeacher) {
        System.out.println(String.format("语文老师【%s】开始上课.", chineseTeacher.name));
    }

    @Override
    public void visitorEnglishTeacher(EnglishTeacher englishTeacher) {
        System.out.println(String.format("英语老师【%s】开始上课.", englishTeacher.name));
    }

    @Override
    public void visitorMathTeacher(MathTeacher mathTeacher) {
        System.out.println(String.format("数学老师【%s】开始上课.", mathTeacher.name));
    }
}

/**
 * @program: visitor
 * @description: 布置作业访问者
 *              具体访问者(Concrete Visitor)
 * @author: wxw
 * @create: 2024-03-14 16:37
 **/
public class AssignHomeworkVisitor implements IActionVisitor {
    @Override
    public void visitorChineseTeacher(ChineseTeacher chineseTeacher) {
        System.out.println(String.format("语文老师【%s】开始布置作业.", chineseTeacher.name));
    }

    @Override
    public void visitorEnglishTeacher(EnglishTeacher englishTeacher) {
        System.out.println(String.format("英语老师【%s】开始布置作业.", englishTeacher.name));
    }

    @Override
    public void visitorMathTeacher(MathTeacher mathTeacher) {
        System.out.println(String.format("数学老师【%s】开始布置作业.", mathTeacher.name));
    }
}

/**
 * @program: visitor
 * @description: 批改作业访问者
 *              具体访问者(Concrete Visitor)
 * @author: wxw
 * @create: 2024-03-14 16:37
 **/
public class HomeworkCorrectingVisitor implements IActionVisitor {
    @Override
    public void visitorChineseTeacher(ChineseTeacher chineseTeacher) {
        System.out.println(String.format("语文老师【%s】开始批改作业.", chineseTeacher.name));
    }

    @Override
    public void visitorEnglishTeacher(EnglishTeacher englishTeacher) {
        System.out.println(String.format("英语老师【%s】开始批改作业.", englishTeacher.name));
    }

    @Override
    public void visitorMathTeacher(MathTeacher mathTeacher) {
        System.out.println(String.format("数学老师【%s】开始批改作业.", mathTeacher.name));
    }
}

结构对象(Object Struture)

/**
 * @program: visitor
 * @description: 培训机构对象结构
 *              结构对象(Object Struture)
 * @author: wxw
 * @create: 2024-03-14 16:43
 **/
public class TrainingAgency {

    private List<Teacher> teacherList = new ArrayList<>();

    public void addTeacher(Teacher teacher){
        teacherList.add(teacher);
    }

    public void removeTeacher(Teacher teacher){
        teacherList.remove(teacher);
    }

    public void startWork(IActionVisitor visitor){
        System.out.println("================================");
        for (Teacher t: teacherList) {
            t.accept(visitor);
        }
        System.out.println("================================");
    }
}

客户端

public class Test {

    public static void main(String[] args) {
        TrainingAgency trainingAgency = new TrainingAgency();
        trainingAgency.addTeacher(new ChineseTeacher("张三"));
        trainingAgency.addTeacher(new EnglishTeacher("李四"));
        trainingAgency.addTeacher(new MathTeacher("王五"));

        // 备课访问者
        IActionVisitor prepareLessonsVisitor = new PrepareLessonsVisitor();
        trainingAgency.startWork(prepareLessonsVisitor);

        // 上课访问者
        IActionVisitor giveClassVisitor = new GiveClassVisitor();
        trainingAgency.startWork(giveClassVisitor);

        // 布置作业访问者
        IActionVisitor assignHomeworkVisitor = new AssignHomeworkVisitor();
        trainingAgency.startWork(assignHomeworkVisitor);

        // 批改作业访问者
        IActionVisitor homeworkCorrectingVisitor = new HomeworkCorrectingVisitor();
        trainingAgency.startWork(homeworkCorrectingVisitor);
    }
}

增加沟通访问者,无需修改Teacher相关的类

/**
 * @program: visitor
 * @description: 与学生沟通访问者
 *              具体访问者(Concrete Visitor)
 * @author: wxw
 * @create: 2024-03-14 16:37
 **/
public class CommunicationVisitor implements IActionVisitor {
    @Override
    public void visitorChineseTeacher(ChineseTeacher chineseTeacher) {
        System.out.println(String.format("语文老师【%s】开始与学生沟通.", chineseTeacher.name));
    }

    @Override
    public void visitorEnglishTeacher(EnglishTeacher englishTeacher) {
        System.out.println(String.format("英语老师【%s】开始与学生沟通.", englishTeacher.name));
    }

    @Override
    public void visitorMathTeacher(MathTeacher mathTeacher) {
        System.out.println(String.format("数学老师【%s】开始与学生沟通.", mathTeacher.name));
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

实现微服务:匹配系统

HTTP与WebSocket协议 1. HTTP协议是无状态的&#xff0c;每次请求都是独立的&#xff0c;服务器不会保存客户端的状态信息。而WebSocket协议是有状态的&#xff0c;一旦建立连接后&#xff0c;服务器和客户端可以进行双向通信&#xff0c;并且可以保持连接状态&#xff0c;服务…

“遥感+”多技术融合:碳排放监测的创新路径“

在全球环境问题日益严重的今天&#xff0c;以全球变暖为主要特征的气候变化成为了人类面临的巨大挑战。它威胁着地球的生态平衡&#xff0c;对全球可持续发展构成了严峻的挑战。为了应对这一挑战&#xff0c;各国纷纷采取行动&#xff0c;致力于实现碳达峰和碳中和的目标。 在…

Window11安装达梦数据库

由于现在流行国产化&#xff0c;很多公司的数据库产品都使用了国产数据库&#xff0c;所以&#xff0c;今天给大家讲解一下&#xff0c;达梦数据库的安装和试用&#xff0c;这样学完以后&#xff0c;就可以直接在公司里面用了。 首先&#xff0c;需要先注册账号&#xff0c;然…

怎么在家里远程控制公司电脑?

在家远程控制公司办公电脑需求渐增 在家工作也被称为远程办公&#xff0c;可以节省通勤时间&#xff0c;而且也为老板提供了对应的工作成果&#xff0c;是一个一举两得的好方法。 如果您想要在家远程控制公司电脑&#xff0c;先需要在公司的电脑上安装并运行相应的远程工具&a…

css设置选中文字和选中图片字的颜色

要改变页面中选中文字的颜色&#xff0c;可以使用 CSS 的 ::selection 伪元素来实现 *::selection {/* 改变选中文字的背景色 */background-color: #c42121;/* 改变选中文字的文本颜色 */color: #fff; } 用通配符选择器给所有元素都加上了 ::selection伪元素&#xff0c;用于…

CrossOver24软件免费电脑虚拟机,快速在Mac和Linux上运行Windows软件

当然&#xff0c;除了之前提到的核心技术、兼容性和性能优化外&#xff0c;CrossOver2024还具有其他一些值得关注的性能特点&#xff1a; CrossOver Mac-安装包下载如下&#xff1a;https://wm.makeding.com/iclk/?zoneid50028 CrossOver linux-安装包下载如下&#xff1a;ht…

工业界真实的推荐系统(小红书)-离散特征处理、矩阵补充模型、双塔模型

课程特点&#xff1a;系统、清晰、实用&#xff0c;原理和落地经验兼具 b站&#xff1a;https://www.bilibili.com/video/BV1HZ421U77y/?spm_id_from333.337.search-card.all.click&vd_sourceb60d8ab7e659b10ea6ea743ede0c5b48 讲义&#xff1a;https://github.com/wangsh…

linux系统创建私有容器仓库和docker容器的资源限制

私有仓库创建和资源限制 创建私有仓库docker资源限制系统压力测试工具stresscpu资源限制限制CPU Share限制CPU核数CPU绑定 mem资源限制限制IO 创建私有仓库 上传harbor压缩包 解压 下载docker-compose 进入解压后的目录 修改配置文件 mv harbor.yml.tmpl harbor.yml vim harb…

Unity3d Shader篇(十四)— 卡通着色

文章目录 前言一、什么是卡通着色&#xff1f;1. 卡通着色原理2. 卡通着色优缺点优点&#xff1a;缺点&#xff1a; 二、使用步骤1. Shader 属性定义2. SubShader 设置3. 卡通轮廓 Pass4. 卡通主 Pass 三、效果四、总结 前言 卡通着色是一种常见的图形渲染效果&#xff0c;它将…

大语言模型:Query Rewriting for Retrieval-Augmented Large Language Models

总体思路 作者首先指出大语言模型虽然取得了很好的效果&#xff0c;但是仍然存在幻觉和时间顺序混乱的问题&#xff0c;因此需要额外知识库和LLM内部知识库相结合&#xff0c;来修正&#xff1b;因此优化传统的retriever-reader的方案成为需要&#xff1b;目前的研究方案当中使…

Nginx的日志怎么看,在哪看,access.log日志内容详解

Nginx 的日志文件通常位于服务器的文件系统中&#xff0c;具体位置可能因配置而异。以下是查看 Nginx 日志的几种方法&#xff1a; 1、查看访问日志&#xff1a;在默认配置下&#xff0c;Nginx 的访问日志文件路径为 /var/log/nginx/access.log。您可以通过命令 sudo cat /var…

前端框架vue的样式操作,以及vue提供的属性功能应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

【2024-完整版】python爬虫 批量查询自己所有CSDN文章的质量分:附整个实现流程

【2024】批量查询CSDN文章质量分 写在最前面一、分析获取步骤二、获取文章列表1. 前期准备2. 获取文章的接口3. 接口测试&#xff08;更新重点&#xff09; 三、查询质量分1. 前期准备2. 获取文章的接口3. 接口测试 四、python代码实现1. 分步实现2. 批量获取文章信息3. 从exce…

必看 11个AI自动写作神器

AI自动写作神器是当今科技发展中的重大突破&#xff0c;能够以人工智能技术为基础&#xff0c;自动生成高质量的文章。下面将介绍10个AI自动写作神器&#xff0c;看看他们有哪些值得推荐的地方&#xff1f; 一、爱制作ai写作生成器 爱制作AI运用先进的文字生成式AI技术&#xf…

visualvm连接到远程服务

启动命令 java -Dcom.sun.management.jmxremote.rmi.port1232 \ -Dcom.sun.management.jmxremote.port1232 \ -Dcom.sun.management.jmxremote.sslfalse \ -Dcom.sun.management.jmxremote.authenticatefalse \ -jar ${你的jar包名}.jar参数说明 java \ #指定JMX RMI (Re…

2048.神、上帝以及老天爷

典型的错排问题 题解&#xff1a;计算所有人错排的种类数/阶乘 错排种类数&#xff1a; 1——0 2——1 3——2 第一个人两种选择假设1拿了2的&#xff0c;那么2只能拿3&#xff0c;因为2如果拿1&#xff0c;3就会拿3就不会拿错 4——9 3(12) 5——44 f(n)(n-1)*[f(n-1)…

尝试搭建谷粒商城 记录(二)

1、后台管理系统 1.整合renren-fast 在记录&#xff08;一&#xff09;中&#xff0c;我们已经基本配置好了一些环境 &#xff0c;后续有需要再补充吧 下载renren-fast &#xff0c;把文件夹复制到gulimall文件夹下&#xff0c; 然后修改父pom.xml文件加入这个module 修改renre…

如何使用vscode创建Node.js服务并结合内网穿透实现远程访问本地服务

文章目录 前言1.安装Node.js环境2.创建node.js服务3. 访问node.js 服务4.内网穿透4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口 5.固定公网地址 前言 Node.js 是能够在服务器端运行 JavaScript 的开放源代码、跨平台运行环境。Node.js 由 OpenJS Foundation&#xff0…

如何在Linux系统部署APITable容器并实现无公网IP远程管理本地数据

文章目录 前言1. 部署APITable2. cpolar的安装和注册3. 配置APITable公网访问地址4. 固定APITable公网地址 前言 vika维格表作为新一代数据生产力平台&#xff0c;是一款面向 API 的智能多维表格。它将复杂的可视化数据库、电子表格、实时在线协同、低代码开发技术四合为一&am…