设计模式1-访问者模式

访问者模式是一种行为设计模式,它允许你定义在对象结构中的元素上进行操作的新操作,而无需修改这些元素的类。这种模式的主要思想是将算法元素的结构分离开,使得可以在不修改元素结构的情况下定义新的操作。

所谓算法与元素结构分离,即保持元素(被访问对象)结构的稳定,而将算法置于访问者之中,因为访问者可以新建,这样就符合了OCP(开闭原则)。

在访问者模式中,有两个主要的角色:

  1. 访问者(Visitor)
    定义了在对象结构中访问元素时的新操作接口。通常会有多个不同的访问者,每个访问者实现一组特定的操作。

  2. 元素(Element)
    定义了接受访问者的接口,通常会有多个不同的元素,每个元素实现了接口并提供了接受访问者的方法。

访问者模式的主要优势在于当需要在一组对象上执行一些复杂的操作时,你可以通过添加新的访问者而不是修改每个元素的类来扩展系统。

类图:

下面是一个简单的 Java 示例,演示了访问者模式的基本结构:

// 访问者接口
interface Visitor {
    void visit(ElementA elementA);
    void visit(ElementB elementB);
}

// 元素接口
interface Element {
    void accept(Visitor visitor);
}

// 具体的元素A
class ElementA implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    
    // 元素A的特定操作
    void operationA() {
        System.out.println("Performing operation A on ElementA");
    }
}

// 具体的元素B
class ElementB implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    
    // 元素B的特定操作
    void operationB() {
        System.out.println("Performing operation B on ElementB");
    }
}

// 具体的访问者
class ConcreteVisitor implements Visitor {
    @Override
    public void visit(ElementA elementA) {
        elementA.operationA();
    }

    @Override
    public void visit(ElementB elementB) {
        elementB.operationB();
    }
}

// 客户端代码
public class VisitorPatternExample {
    public static void main(String[] args) {
        Element elementA = new ElementA();
        Element elementB = new ElementB();

        Visitor visitor = new ConcreteVisitor();

        elementA.accept(visitor); // 执行 ElementA 的操作
        elementB.accept(visitor); // 执行 ElementB 的操作
    }
}

在这个例子中,Visitor 接口定义了两个访问方法,每个方法对应一个具体的元素。Element 接口定义了接受访问者的方法。具体的元素类 ElementAElementB 实现了 Element 接口,并分别实现了自己的特定操作。ConcreteVisitor 是一个具体的访问者类,实现了对每个元素的访问操作。

在客户端代码中,我们创建了一个 ConcreteVisitor 实例,并让每个元素接受这个访问者。换言之,是在Client中操作了访问者与元素的连接印证了类图。这样,通过不同的访问者,我们可以执行不同的操作,而不需要修改元素的类。这是访问者模式的一种简单示例,实际中可能涉及更复杂的场景和多个元素。

怎么定义新的操作?

当使用访问者模式时,定义新的操作就是创建新的实现了访问者接口的具体访问者类。每个具体访问者类负责实现一组特定的操作,而这些操作可以是全新的、与原有操作不相关的,或者是对现有操作的扩展。

举个例子,假设我们有一个图形结构,包括圆形(Circle)和矩形(Rectangle)两种图形。现在我们希望实现两种不同的操作:计算图形的面积和计算图形的周长。

首先,定义图形接口和具体的图形类:

// 图形接口
interface Shape {
    void accept(Visitor visitor);
}

// 圆形类
class Circle implements Shape {
    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    public double getRadius() {
        return radius;
    }

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

// 矩形类
class Rectangle implements Shape {
    private double width;
    private double height;

    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }

    public double getWidth() {
        return width;
    }

    public double getHeight() {
        return height;
    }

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

然后,定义访问者接口和具体的访问者类:

// 访问者接口
interface Visitor {
    void visit(Circle circle);
    void visit(Rectangle rectangle);
}

// 计算面积的具体访问者类
class AreaCalculator implements Visitor {
    @Override
    public void visit(Circle circle) {
        double area = Math.PI * circle.getRadius() * circle.getRadius();
        System.out.println("Area of Circle: " + area);
    }

    @Override
    public void visit(Rectangle rectangle) {
        double area = rectangle.getWidth() * rectangle.getHeight();
        System.out.println("Area of Rectangle: " + area);
    }
}

// 计算周长的具体访问者类
class PerimeterCalculator implements Visitor {
    @Override
    public void visit(Circle circle) {
        double perimeter = 2 * Math.PI * circle.getRadius();
        System.out.println("Perimeter of Circle: " + perimeter);
    }

    @Override
    public void visit(Rectangle rectangle) {
        double perimeter = 2 * (rectangle.getWidth() + rectangle.getHeight());
        System.out.println("Perimeter of Rectangle: " + perimeter);
    }
}

现在我们可以在不修改图形类的情况下定义新的操作。例如,创建了两个具体的访问者类 AreaCalculatorPerimeterCalculator 分别用于计算图形的面积和周长。在客户端代码中,我们可以通过接受不同的访问者来执行不同的操作:

public class VisitorExample {
    public static void main(String[] args) {
        Shape circle = new Circle(5);
        Shape rectangle = new Rectangle(4, 6);

        Visitor areaCalculator = new AreaCalculator();
        Visitor perimeterCalculator = new PerimeterCalculator();

        circle.accept(areaCalculator); // 计算圆形的面积
        circle.accept(perimeterCalculator); // 计算圆形的周长

        rectangle.accept(areaCalculator); // 计算矩形的面积
        rectangle.accept(perimeterCalculator); // 计算矩形的周长
    }
}

这样,通过定义不同的访问者,我们可以轻松地扩展系统,而无需修改图形类的结构。

结论:

访问者模式很好地实现了访问算法开放被访问元素封闭,有这种需求时就可以考虑使用访问者模式。

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

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

相关文章

css1文本属性

一.颜色(color)(一般用16进制) 二.对齐(text-align) 三.装饰(text-decoration) 四.缩进(text-indent)(一般用2em)(有单位)…

面试数据结构与算法总结分类+leetcode目录【基础版】

🧡🧡🧡算法题目总结: 这里为大家总结数据结构与算法的题库目录,如果已经解释过的题目会标注链接更新,方便查看。 数据结构概览 Array & String 大家对这两类肯定比较清楚的,同时这也是面试…

idea中找到所有的TODO

idea中找到所有的TODO (1)快捷键 Alt6 (2)View -> Tool Windows -> TODO

【Chrono Engine学习总结】1-安装配置与程序运行

本文仅用于个人安装记录。 官方安装教程 https://api.projectchrono.org/8.0.0/tutorial_install_chrono.html Windows下安装 windows下安装就按照教程好了。采用cmake-gui进行配置,建议首次安装只安装核心模块。然后依此configure下irrlicht,sensor…

正则表达式可视化工具regex-vis

什么是正则表达式 ? 正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。【百度百科】 正则表达式用简短…

python 视频硬字幕去除 内嵌字幕去除工具vsr

项目简介 开源地址:https://github.com/YaoFANGUK/video-subtitle-remover Video-subtitle-remover (VSR) 是一款基于AI技术,将视频中的硬字幕去除的软件。 主要实现了以下功能: 无损分辨率将视频中的硬字幕去除,生成去除字幕后…

《学成在线》微服务实战项目实操笔记系列(P1~P49)【上】

《学成在线》项目实操笔记系列【上】,跟视频的每一P对应,全系列12万字,涵盖详细步骤与问题的解决方案。如果你操作到某一步卡壳,参考这篇,相信会带给你极大启发。同时也欢迎大家提问与讨论,我会尽力帮大家解…

小华和小为的聚餐地点 - 华为OD统一考试

OD统一考试(C卷) 分值: 200分 题解: Java / Python / C++ 题目描述 小华和小为是很要好的朋友,他们约定周末一起吃饭。 通过手机交流,他们在地图上选择了多个聚餐地点(由于自然地形等原因,部分聚餐地点不可达)。 求小华和小为都能到达的聚餐地点有多少个? 输入描述…

【小白开服日记】幻兽帕鲁服务器如何搭建?

玩转幻兽帕鲁服务器,阿里云推出新手0基础一键部署幻兽帕鲁服务器教程,傻瓜式一键部署,3分钟即可成功创建一台Palworld专属服务器,成本仅需26元,阿里云服务器网aliyunfuwuqi.com分享2024年新版基于阿里云搭建幻兽帕鲁服…

代码编辑器1.9.0

多线程&#xff01;&#xff01;&#xff01; #include <winsock2.h> #include <windows.h> #include <iostream> #include <stdlib.h> #include <string.h> #include <fstream> #include <conio.h> #include <stdio.h> #incl…

Java并发(二十三)----同步模式之保护性暂停

1、定义 即 Guarded Suspension&#xff0c;用在一个线程等待另一个线程的执行结果 要点 有一个结果需要从一个线程传递到另一个线程&#xff0c;让他们关联同一个 GuardedObject 如果有结果不断从一个线程到另一个线程那么可以使用消息队列 JDK 中&#xff0c;join 的实现…

嵌入式学习第十六天!(Linux文件查看、查找命令、标准IO)

Linux软件编程 1. Linux&#xff1a; 操作系统的内核&#xff1a; 1. 管理CPU 2. 管理内存 3. 管理硬件设备 4. 管理文件系统 5. 任务调度 2. Shell&#xff1a; 1. 保护Linux内核&#xff08;用户和Linux内核不直接操作&#xff0c;通过操作Shell&#xff0c;Shell和内核交互…

Ubuntu Linux 下安装和卸载cmake 3.28.2版本

一、安装cmake 1.首先&#xff0c;先从cmake官网下载cmake-3.28.2-linux-x86_64.tar.gz 2.用FinalShell 等文件上传工具&#xff0c;将这个压缩包上传到 虚拟机的某个路径去&#xff08;自选&#xff09; 3. cd /usr/local/bin/&#xff0c;然后创建cmake文件夹&#xff0c;…

重温《深入理解Java虚拟机:JVM高级特性与最佳实践(第二版)》 –– 学习笔记(二)

第二部分&#xff1a;自动内存管理机制 第2章&#xff1a;Java内存区域与内存溢出异常 2.1 概述 Java 与 C 之间有一堵由内存动态分配和垃圾收集技术围成的高墙。 Java 程序员在 虚拟机自动内存管理机制 的帮助下&#xff0c;无需为每一个 new 操作去写配对的 delete/free …

Cox等级资料是个坑

R语言做&#xff01;初学者先进来看看&#xff01;&#xff01;&#xff01; SCI冲 COX多因素模型需要满足的条件&#xff1a; 1.各观测值间相互独立&#xff0c;即残差之间不存在自相关&#xff1b; 2.因变量和自变量之间存在线性关系&#xff1b; 3.残差的方差齐&#xf…

鸿蒙ArkUI实现开关switch组件

鸿蒙ArkUI官方提供的toggle组件实现了开关的样式&#xff0c;但在使用过程中还是非常的不方便。 DIY可视化对鸿蒙ArkUI实现开关switch组件扩展后满足基本的switch需求&#xff0c;支持绑定值、设置标题文本、整个背景样式等。 /*** 开关*/ Component export default struct Di…

Angular BaseView抽离页面公用属性

前言 如果有一系列的页面布局很类似&#xff0c;为了节省时间&#xff0c;我们可以把这些类似的页面所通用的属性和方法抽离成一个BaseView&#xff0c;让其它页面继承该基础页面&#xff0c;同时将一些经常改变的属性和差异的属性写到配置文件里。例如树容器初始时是否展开、…

npm ERR! code CERT_HAS_EXPIRED

执行npm i报错&#xff1a; npm ERR! code ETIMEDOUT npm ERR! syscall connect npm ERR! errno ETIMEDOUT npm ERR! network request to https://registry.npmjs.org/react-redux failed, reason: connect ETIMEDOUT 104.16.2.35:443 npm ERR! network This is a problem rel…

[设计模式Java实现附plantuml源码~结构型]处理多维度变化——桥接模式

前言&#xff1a; 为什么之前写过Golang 版的设计模式&#xff0c;还在重新写Java 版&#xff1f; 答&#xff1a;因为对于我而言&#xff0c;当然也希望对正在学习的大伙有帮助。Java作为一门纯面向对象的语言&#xff0c;更适合用于学习设计模式。 为什么类图要附上uml 因为很…

python_蓝桥杯刷题记录_笔记_全AC代码_入门3

前言 记录我的解法以及笔记思路&#xff0c;谢谢观看。 题单目录 1.P2141 [NOIP2014 普及组] 珠心算测验 2.P1567 统计天数 3.P1055 [NOIP2008 普及组] ISBN 号码 4.P1200 [USACO1.1] 你的飞碟在这儿 Your Ride Is Here 5.P1308 [NOIP2011 普及组] 统计单词数 6.P1047 […