【设计模式深度剖析】【9】【行为型】【访问者模式】| 以博物馆的导览员为例加深理解

news2024/10/6 16:19:03

👈️上一篇:备忘录模式

设计模式-专栏👈️


文章目录

  • 访问者模式
  • 定义
    • 英文原话
    • 直译
    • 如何理解呢?
  • 访问者模式的角色
    • 类图
    • 代码示例
  • 访问者模式的应用
    • 优点
    • 缺点
    • 使用场景
  • 示例解析:博物馆的导览员
    • 代码示例

访问者模式

访问者模式(Visitor Pattern)就像一位多才多艺的导游,能够根据不同的景点(数据结构中的元素)提供个性化的解说服务(操作),而无需改变景点的本质。

定义

英文原话

The Visitor pattern is a behavioral design pattern that allows you to add new operations to objects without changing their classes. A visitor is a class with methods that correspond to the classes of an object structure it visits. A client uses the visitor to perform the operations on the elements of the object structure.

直译

访问者模式是一种行为设计模式,它允许你在不改变对象类的情况下为对象添加新的操作。访问者是一个类,它包含的方法对应于它所访问的对象结构中的类。客户端使用访问者来对对象结构的元素执行操作。

如何理解呢?

想象一下你有一个装满各种形状(圆形、矩形、三角形)的盒子。现在你想对这些形状进行不同的操作,比如测量它们的面积或周长。使用访问者模式,你可以创建一个“测量工具”(即访问者),它知道如何与每种形状交互并获取所需的信息,而不需要改变形状本身。

访问者模式的角色

访问者模式中的角色包括:

  1. Visitor(访问者):这是一个接口或抽象类,声明了访问特定元素类时需要执行的操作。
  2. ConcreteVisitor(具体访问者):实现了Visitor接口或继承了Visitor抽象类,实现了对元素类中每个元素的访问操作。
  3. Element(元素):这是一个接口或抽象类,声明了一个接受访问者对象的方法(通常是accept)。
  4. ConcreteElement(具体元素):实现了Element接口或继承了Element抽象类,并实现accept方法以接受访问者的访问。
  5. ObjectStructure(对象结构):能够枚举它的元素,并可以提供一个高层接口以允许访问者访问它的元素。这通常是一个集合类,如列表或树。

类图

在这里插入图片描述

代码示例

package com.polaris.designpattern.list3.behavioral.pattern09.visitor.classicdemo;

import java.util.ArrayList;
import java.util.List;

// Visitor 接口
interface Visitor {
    void visit(ConcreteElementA element);

    void visit(ConcreteElementB element);
}

// ConcreteVisitor 类  
class ConcreteVisitor implements Visitor {
    @Override
    public void visit(ConcreteElementA element) {
        System.out.println("Visiting ConcreteElementA: " + element.operationA());
    }

    @Override
    public void visit(ConcreteElementB element) {
        System.out.println("Visiting ConcreteElementB: " + element.operationB());
    }
}

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

// ConcreteElementA 类  
class ConcreteElementA implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    public String operationA() {
        return "elementA info...";
    }
}

// ConcreteElementB 类  
class ConcreteElementB implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    public String operationB() {
        return "elementB info...";
    }
}

// ObjectStructure 类(这里简单用ArrayList作为示例)

class ObjectStructure {
    private List<Element> elements = new ArrayList<>();

    public void add(Element element) {
        elements.add(element);
    }

    public void accept(Visitor visitor) {
        for (Element element : elements) {
            element.accept(visitor);
        }
    }
}

// 客户端代码  
public class VisitorPatternDemo {
    public static void main(String[] args) {
        ObjectStructure objectStructure = new ObjectStructure();
        objectStructure.add(new ConcreteElementA());
        objectStructure.add(new ConcreteElementB());

        Visitor visitor = new ConcreteVisitor();
        objectStructure.accept(visitor);
    }
}
/* Output:
Visiting ConcreteElementA: elementA info...
Visiting ConcreteElementB: elementB info...
*///~

在这个示例中,我们有一个Visitor接口和两个具体的访问者方法(对应于两种不同类型的元素)。我们还有两个实现了Element接口的ConcreteElement类,它们各自有自己的操作。ObjectStructure类管理了一个Element对象的集合,并提供了一个accept方法来遍历这些对象并接受访问者的访问。在客户端代码中,我们创建了一个ObjectStructure对象,并向其中添加了两个不同类型的元素。然后,我们创建了一个ConcreteVisitor对象,并使用它来访问ObjectStructure中的所有元素。

访问者模式的应用

访问者模式是一种设计模式,它允许在不改变数据结构的前提下,为数据结构中的每个元素定义新的操作。这种模式在需要为数据结构中的元素添加新行为,但又不想修改这些元素所在类的情况下特别有用。

优点

  1. 扩展性好:当需要为数据结构中的元素添加新操作时,只需定义一个新的访问者类即可,无需修改原有类。
  2. 复用性好:访问者模式可以通过为不同的数据结构定义相同的访问者接口,实现操作的复用。
  3. 灵活性好:访问者模式将数据结构与作用于结构上的操作解耦,使得操作集合可以相对自由地演化而不影响系统的数据结构。
  4. 符合单一职责原则:每个访问者只负责一种操作,使代码更加清晰和易于维护。

缺点

  1. 破坏封装:在访问者模式中,具体元素需要向访问者公开其内部状态和方法,这可能会破坏对象的封装性。
  2. 增加新数据结构困难:当需要为新的数据结构添加访问者时,需要在访问者接口中添加新的方法,这可能会增加代码的复杂性。
  3. 具体元素变更困难:如果具体元素的内部结构发生变化,可能需要修改所有相关的访问者类,这可能会增加维护成本。

使用场景

  1. 电商网站商品分类与操作:电商网站通常有大量的商品,这些商品可以按照不同的属性进行分类。使用访问者模式,可以定义一个访问者对象,它能够访问不同类型的商品对象,并根据需要执行不同的操作,如按照价格排序、根据品牌筛选等。
  2. 图形编辑器的操作处理:在图形编辑器中,有多种图形元素,如线条、圆形、矩形等。访问者模式允许定义一个访问者对象,它能够访问这些图形元素并执行不同的操作,如移动、缩放、旋转或改变颜色等。
  3. 编译器和解释器设计:在编译器或解释器的设计中,抽象语法树(AST)是一个常见的数据结构。使用访问者模式,可以为AST中的不同节点类型定义不同的访问者,以执行如类型检查、代码优化、代码生成等操作。

示例解析:博物馆的导览员

假设你是一家博物馆的导览员,博物馆里有很多不同类型的展品,如绘画、雕塑和古代文物。作为导览员,你需要为不同类型的展品提供不同的解说词。但是,展品的种类可能会随着时间增加或减少,而你不希望每次有新的展品加入时都要重新学习所有的解说词。

在这里,展品可以看作是数据结构中的元素,而导览员就是访问者。导览员(访问者)需要访问不同的展品(元素),并为它们提供解说词(操作)。

代码示例

下面是一个简单的Java代码示例,用于模拟这个场景:

package com.polaris.designpattern.list3.behavioral.pattern09.visitor.demo1;

// 展品接口
interface Artifact {
    void accept(TourGuide tourGuide);
}

// 绘画展品  
class Painting implements Artifact {
    private String name;

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

    @Override
    public void accept(TourGuide tourGuide) {
        tourGuide.visit(this);
    }

    public String getName() {
        return name;
    }
}

// 雕塑展品  
class Sculpture implements Artifact {
    private String name;

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

    @Override
    public void accept(TourGuide tourGuide) {
        tourGuide.visit(this);
    }

    public String getName() {
        return name;
    }
}

// 导览员(访问者)接口  
interface TourGuide {
    void visit(Painting painting);

    void visit(Sculpture sculpture);
    // 如果以后有更多类型的展品,可以在这里添加方法  
}

// 具体导览员类  
class EnglishTourGuide implements TourGuide {
    @Override
    public void visit(Painting painting) {
        System.out.println("This is a painting called " + painting.getName() + ". It is beautiful!");
    }

    @Override
    public void visit(Sculpture sculpture) {
        System.out.println("This is a sculpture called " + sculpture.getName() + ". It is impressive!");
    }
}

// 客户端代码  
public class MuseumDemo {
    public static void main(String[] args) {
        // 创建展品  
        Artifact painting = new Painting("Mona Lisa");
        Artifact sculpture = new Sculpture("Thinker");

        // 创建导览员  
        TourGuide tourGuide = new EnglishTourGuide();

        // 导览员访问展品  
        painting.accept(tourGuide);
        sculpture.accept(tourGuide);
    }
}

/* Output:
This is a painting called Mona Lisa. It is beautiful!
This is a sculpture called Thinker. It is impressive!
*///~

在这个示例中,Artifact是展品接口,PaintingSculpture是具体的展品类。TourGuide是导览员接口,EnglishTourGuide是具体的导览员类。当新的展品类型出现时,只需要实现Artifact接口并添加相应的accept方法,然后在TourGuide接口中添加对应的visit方法即可,而不需要修改已经存在的展品类和导览员类。这样,就实现了在不改变数据结构的前提下,为数据结构中的每个元素定义新的操作。


👈️上一篇:备忘录模式

设计模式-专栏👈️

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

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

相关文章

计算机毕业设计hadoop+spark+hive知识图谱酒店推荐系统 酒店数据分析可视化大屏 酒店爬虫 高德地图API 酒店预测系统 大数据毕业设计

流程&#xff1a; 1.Python爬取去哪儿网全站旅游数据约10万&#xff0c;存入mysql; 2.使用pandasnumpy/hadoopmapreduce对mysql中旅游数据进行数据清洗&#xff0c;使用高德API计算地理信息&#xff0c;最终转为.csv文件上传hdfs; 3.hive建库建表导入.csv文件作为数据集&#x…

2024年汉字小达人活动还有4个多月开赛:来做18道历年选择题备考吧

结合最近几年的活动安排&#xff0c;预计2024年第11届汉字小达人比赛还有4个多月就启动&#xff0c;那么孩子们如何利用这段时间有条不紊地准备汉字小达人比赛呢&#xff1f; 我的建议是充分利用即将到来的暑假&#xff1a;①把小学1-5年级的语文课本上的知识点熟悉&#xff0…

Windows11和Ubuntu22双系统安装指南

一、需求描述 台式机电脑&#xff0c;已有Windows11操作系统&#xff0c;想要安装Ubuntu22系统&#xff08;版本任意&#xff09;。其中Windows安装在Nvme固态上&#xff0c;Ubuntu安装在Sata固态上&#xff0c;双盘双系统。开机时使用Grub控制进入哪个系统&#xff0c;效果图…

直接选择排序-C语言版本

前言 直接选择排序也是一个比较简单的排序&#xff0c;所以这里放在第二个进行讲解&#xff0c;这里和冒泡排序是有一点相似。直接选择排序和冒泡排序一样&#xff0c;也是具备一定的教学意义&#xff0c;但是没有什么实际操作的意义&#xff0c;因为直接选择排序的时间复杂度比…

云原生 Docker Swarm 使用详解

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…

用Copilot画漫画,Luma AI生成视频:解锁创意新玩法

近年来&#xff0c;随着人工智能技术的不断发展&#xff0c;各种创意工具也层出不穷。今天&#xff0c;我们就来介绍一种全新的创作方式&#xff1a;使用Copilot画漫画&#xff0c;再将漫画放入Luma AI生成视频。 Copilot&#xff1a;你的AI绘画助手 Copilot是一款基于人工智…

Java | Leetcode Java题解之第147题对链表进行插入排序

题目&#xff1a; 题解&#xff1a; class Solution {public ListNode insertionSortList(ListNode head) {if (head null) {return head;}ListNode dummyHead new ListNode(0);dummyHead.next head;ListNode lastSorted head, curr head.next;while (curr ! null) {if (…

C++编程:vector容器的简单模拟实现

前言&#xff1a; 在C标准库&#xff08;STL&#xff09;中&#xff0c;vector容器是最常见使用的动态数组。它结合了链表与数组的优点&#xff0c;提供了灵活的大小调整与高效的随机访问。本文将简单的对vector容器进行介绍并且对vector容器简单的模拟实现。 一、vector的文…

Project ERROR: Unknown module(s) in QT: xlsx

Qt5下Qxlsx模块安装及使用_qt5xlsx-CSDN博客 主要参考上面这篇文章&#xff01; Perl的安装与配置_perl安装-CSDN博客 1.1 windows环境安装Perl_windows perl-CSDN博客 首先&#xff0c;需要安装Perl,我安装的是Windows版本的。 Download & Install Perl - ActiveStat…

C#使用Scoket实现服务器和客户端互发信息

20240616 By wdhuag 目录 前言&#xff1a; 参考&#xff1a; 一、服务器端&#xff1a; 1、服务器端口绑定&#xff1a; 2、服务器关闭&#xff1a; 二、客户端&#xff1a; 1、客户端连接&#xff1a; 2、客户端断开&#xff1a; 三、通讯&#xff1a; 1、接收信…

【后端】websocket学习笔记

文章目录 1. 消息推送常见方式1.1 轮询 VS 长轮询1.2 SSE&#xff08;server-sent event)服务器发送事件 2. websocket介绍2.1 介绍2.2 原理2.3 websoket API2.3.1 客户端【浏览器】API2.3.2 服务端API 3. 代码实现3.1 流程分析3.2 pom依赖3.3 配置类3.4 消息格式3.5 消息类 4.…

Qwen2大语言模型微调、导出、部署实践

上篇文章&#xff1a; Qwen1.5大语言模型微调实践_qwen1.5 7b微调-CSDN博客 我们介绍了Qwen1.5 大语言模型使用LLaMA-Factory 来微调&#xff0c;这篇文章我们介绍一下微调后模型的导出、部署。 一、模型导出 在webui 界面训练好模型之后点击“Export”选项卡&#xff0c;然…

Golang | Leetcode Golang题解之第155题最小栈

题目&#xff1a; 题解&#xff1a; type MinStack struct {stack []intminStack []int }func Constructor() MinStack {return MinStack{stack: []int{},minStack: []int{math.MaxInt64},} }func (this *MinStack) Push(x int) {this.stack append(this.stack, x)top : thi…

工程设计问题---压缩弹簧设计

参考文献&#xff1a; [1] 吴擎, 徐惟罡, 张春江. 基于师生交流机制的改进类电磁机制算法[J]. 计算机集成制造系统, 2020, 26(4): 1033-1042.

数电逻辑门电路分析和Digital仿真

文章目录 1. 逻辑门电路 2. 非门&#xff08;NOT Gate&#xff09; 3. 与门&#xff08;AND Gate&#xff09; 4. 或门&#xff08;OR Gate&#xff09; 5. 与非门&#xff08;NAND Gate&#xff09; 6. 或非门&#xff08;NOR Gate&#xff09; 7. 异或门&#xff08;XO…

VMware 桥接网络突然无法上网

VMware 桥接网络突然无法上网 0. 问题1. 解决方法 0. 问题 昨天&#xff0c;VMware 桥接网络正常使用&#xff0c;今天突然无法上网。 1. 解决方法 打开VMware的虚拟网络编辑器&#xff0c;将桥接模式的网络从“自动”改成你要使用的网卡&#xff0c;问题解决。 完成&#…

【CT】LeetCode手撕—88. 合并两个有序数组

目录 题目1- 思路2- 实现⭐88. 合并两个有序数组——题解思路 2- ACM实现 题目 原题连接&#xff1a;88. 合并两个有序数组 1- 思路 模式识别 模式1&#xff1a;两个有序数组合并 ——> 双指针模式2&#xff1a;返回结果填充到 nums1[mn] ——> 需要开辟新的数组空间 …

!力扣46. 全排列

给定一个不含重复数字的数组 nums &#xff0c;返回其所有可能的全排列 。你可以按任意顺序返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] 示例 2&#xff1a; 输入&#xff1a;nu…

【SCAU操作系统】期末复习选择题例题解析

1. ____B_____操作系统能及时处理由过程控制反馈的数据并响应。 A. 分布式 B. 实时 C. 分时 D. 嵌入式 解析&#xff1a; 分布式&#xff1a;分布式操作系统是管理分布式系统的资源的操作系统。实时&#xff1a;实时操作系统&#xff08;RTOS&#x…

一个基于大模型的多功能的本地网页语音合成工具

ChatTTS-ui 是一个开源项目&#xff0c;这是一个利用 ChatTTS 技术将文本转换为语音的本地网页界面工具。它不仅支持中英文和数字的混合输入&#xff0c;还提供了丰富的API接口&#xff0c;为开发者和用户提供了极大的便利。 项目地址&#xff1a;https://github.com/jianchang…