访问者模式(Visitor Pattern)

news2025/3/10 15:11:41

访问者模式

说明

访问者模式(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));
    }
}

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

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

相关文章

蓝牙系列十三:协议栈L2CAP层

L2CAP 全称为逻辑链路控制与适配协议(Logical Link Control and Adaptation Protocol)&#xff0c;位于基带层之上&#xff0c;将基带层的数据分组交换为便于高层应用的数据分组格式&#xff0c;并提供协议复用和服务质量交换等功能。 该层属于主机的内容&#xff0c;位于HCI层…

3.3 ss-sp寄存器,栈的push和pop指令

汇编语言 1. 栈 栈是一种具有特殊的访问方式的存储空间它的特殊性就在于&#xff0c;最后进入这个空间的数据&#xff0c;最先出去。即先进后出 1.1 栈的基本操作 入栈&#xff1a;入栈就是将一个新的元素放到栈顶出栈&#xff1a;出栈就是从栈顶取出一个元素栈顶的元素总是…

汽车电子零部件(4):行泊一体ADAS

前言: 现阶段智能汽车行业正在大规模力推无限接近于L3的L2++或L2.9自动驾驶量产落地,类似于当初智能手机替换传统手机的行业机会期。智能汽车常见的智能驾驶功能包括: 行车场景:自适应巡航控制ACC;自动变道辅助ALC;交通拥堵辅助TJA;车道居中LCC;领航辅助NOA; 泊车场…

如何在代理的IP被封后立刻换下一个IP继续任务

目录 前言 1. IP池准备 2. 使用代理IP进行网络请求 3. 处理IP被封的情况 4. 完整代码示例 总结 前言 当进行某些网络操作时&#xff0c;使用代理服务器可以帮助我们隐藏真实IP地址以保护隐私&#xff0c;或者绕过一些限制。然而&#xff0c;经常遇到的问题是代理的IP可能…

AI新工具(20240313) 用户输入提示词创建任何GIF; 将任意人脸图片转换为另一幅图像的模型

✨ 1: GifShift 用户输入提示词创建任何GIF gifshift是一种工具&#xff0c;可以帮助用户创建任何GIF的新版本。使用gifshift的步骤如下&#xff1a; 上传一个GIF文件或者使用库中的一个GIF。 提供您想要的场景描述&#xff0c;最好选择一些具有代表性的角色&#xff0c;并进…

Android cmdline tools安装

打开AS 进入SDK Tools 看到了吗?那个打着勾的就是

从零开始搭建医保购药APP:技术选择与开发流程

医保购药APP作为一种创新的医疗服务工具&#xff0c;为用户提供了便捷的医保购药流程&#xff0c;同时也为医疗机构提供了更高效的管理和服务方式。今天小编将为大家讲解如何从零开始搭建一款医保购药APP&#xff0c;包括技术选择和开发流程。 一、技术选择 在搭建医保购药APP…

DS进阶:二叉搜索树

创作不易&#xff0c;感谢三连&#xff01; 一、二叉搜索树的概念 思考&#xff1a; 为什么二叉搜索树也叫做二叉查找树和二叉排序树呢&#xff1f;&#xff1f; 1、 本身树形结构用来存储数据相比顺序表和链表来说并不占有优势&#xff0c;他的最大优势就在于查找优势&…

Python面向对象构造函数:手把手教你如何玩转对象初始化

我们都知道&#xff0c;Python是一个面向对象的语言&#xff0c;这意味着我们可以用类来定义对象的属性和方法。而构造函数&#xff0c;就是当我们创建一个新的对象时&#xff0c;会自动调用的特殊方法。那么&#xff0c;如何玩转这个构造函数呢&#xff1f; 首先&#xff0c;…

DOM事件event/冒泡/委派/取消默认行为/dataset属性

1DOM获取CSS样式表里的样式: <head><meta charset"UTF-8"><title>Title</title><link rel"stylesheet" href"css/style.css"><style>body{color: red;}h1::after{content: hello;color: red;}</style&g…

微博热搜榜单采集,微博热搜榜单爬虫,微博热搜榜单解析,完整代码(话题榜+热搜榜+文娱榜和要闻榜)

文章目录 代码1. 话题榜2. 热搜榜3. 文娱榜和要闻榜 过程1. 话题榜2. 热搜榜3. 文娱榜和要闻榜 代码 1. 话题榜 import requests import pandas as pd import urllib from urllib import parse headers { authority: weibo.com, accept: application/json, text/pl…

《JAVA与模式》之工厂方法模式

系列文章目录 文章目录 系列文章目录前言一、工厂方法模式二、工厂方法模式的活动序列图三、工厂方法模式和简单工厂模式前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码…

SwiftU的组件 - TabView

SwiftU的组件 - TabView 记录一下SwiftU的组件 - TabView的两种style分别的使用方式 import SwiftUIstruct TabViewBootCamp: View {State var selectedIndex 0var body: some View {NavigationView {TabView(selection: $selectedIndex) {HomeView(selectedIndex: $selected…

【解读】Synopsys发布2024年开源安全和风险分析报告OSSRA

软件供应链管理中&#xff0c;许可证和安全合规性至关重要。开源组件和库可降低风险&#xff0c;但需了解许可证内容。Synopsys 2023年审计发现&#xff0c;超过一半的代码库存在许可证冲突。MIT许可证是最常用的宽松许可证&#xff0c;但也与其他许可证存在不兼容风险。点此获…

重学SpringBoot3-Problemdetails

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 重学SpringBoot3-Problemdetails Problem Details的概念ProblemDetails配置类在Spring Boot 3中使用Problem Details未配置Problem Details配置Problem Details自定义异常…

外包就干了2个月,技术退步明显....

先说情况&#xff0c;大专毕业&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试&#xf…

程序员必备开发工具、程序员必备集成开发环境(IDE)

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

鸿蒙Next学习-Flex布局

Entry Component struct FlexCase {build() {//需要在构造参数上传Flex({ direction: FlexDirection.Row,justifyContent:FlexAlign.Center }) {//flex布局Row().width(100).height(100).backgroundColor(Color.Red)Row().width(100).height(100).backgroundColor(Color.Yellow…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:NavRouter)

导航组件&#xff0c;默认提供点击响应处理&#xff0c;不需要开发者自定义点击事件逻辑。 说明&#xff1a; 该组件从API Version 9开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 必须包含两个子组件&#xff0c;其中第二个子组…