GPT带我学-设计模式18-访问者模式

embedded/2024/10/20 10:14:46/

概述

访问者模式(Visitor Pattern)是一种行为型设计模式,用于将操作封装到一个访问者对象中,从而可以对不同类型的元素进行操作,而不需要改变这些元素的类。

主要应用场景

访问者模式的主要应用场景包括:

  1. 操作对象结构: 当你需要对一个复杂的对象结构(如树形结构)进行多次操作,而这些操作可能会变化时,使用访问者模式可以避免在对象类中添加过多的方法。

  2. 分离数据结构与操作: 当你希望将数据结构(如对象)与操作(如对这些对象的行为)分离时,访问者模式可以让你在不改变数据结构的情况下,轻松增加新的操作。

  3. 需要访问多个类的行为: 当你有一组相关的类,并且需要对每个类执行不同的操作时,访问者模式能够提供清晰的组织结构,使代码更易于维护。

  4. 频繁变化的操作: 如果操作频繁变化而对象结构相对稳定,使用访问者模式可以避免对每个类进行修改,从而降低维护成本。

  5. 复杂的对象结构: 在处理复杂的对象结构时(例如抽象语法树、文件系统等),访问者模式能够提供一种清晰的方式来进行遍历和操作。

示例应用场景

  • 编译器设计: 编译器可以使用访问者模式来处理不同类型的抽象语法树节点,执行语义分析或代码生成。
  • 图形编辑器: 在图形编辑器中,访问者模式可以用于处理各种形状的操作(如绘制、测量面积等)。
  • 文件系统: 在文件管理系统中,可以使用访问者模式来计算文件大小、打印文件信息等。

如果你有具体的场景或需求,想讨论如何应用访问者模式,请告诉我!

示例1 计算图形面积和周长

结构

  1. 元素接口(Element):定义一个接受访问者的接口。
  2. 具体元素(ConcreteElement):实现元素接口的类,代表被访问的对象。
  3. 访问者接口(Visitor):定义一个访问方法,每个具体元素类都有一个对应的访问方法。
  4. 具体访问者(ConcreteVisitor):实现访问者接口,定义对每种具体元素的操作。

示例代码

假设我们有一个图形处理系统,其中有不同的图形元素(如圆形和矩形),我们希望计算它们的面积和周长。

// 元素接口
interface Shape {void accept(Visitor visitor);
}// 具体元素:圆形
class Circle implements Shape {private double radius;public Circle(double radius) {this.radius = radius;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}public double getRadius() {return radius;}
}// 具体元素:矩形
class Rectangle implements Shape {private double width;private double height;public Rectangle(double width, double height) {this.width = width;this.height = height;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}public double getWidth() {return width;}public double getHeight() {return height;}
}// 访问者接口
interface Visitor {void visit(Circle circle);void visit(Rectangle rectangle);
}// 具体访问者:计算面积
class AreaVisitor implements Visitor {@Overridepublic void visit(Circle circle) {double area = Math.PI * Math.pow(circle.getRadius(), 2);System.out.println("Circle area: " + area);}@Overridepublic void visit(Rectangle rectangle) {double area = rectangle.getWidth() * rectangle.getHeight();System.out.println("Rectangle area: " + area);}
}// 具体访问者:计算周长
class PerimeterVisitor implements Visitor {@Overridepublic void visit(Circle circle) {double perimeter = 2 * Math.PI * circle.getRadius();System.out.println("Circle perimeter: " + perimeter);}@Overridepublic void visit(Rectangle rectangle) {double perimeter = 2 * (rectangle.getWidth() + rectangle.getHeight());System.out.println("Rectangle perimeter: " + perimeter);}
}// 使用示例
public class Main {public static void main(String[] args) {Shape circle = new Circle(5);Shape rectangle = new Rectangle(4, 6);Visitor areaVisitor = new AreaVisitor();Visitor perimeterVisitor = new PerimeterVisitor();// 计算面积circle.accept(areaVisitor);rectangle.accept(areaVisitor);// 计算周长circle.accept(perimeterVisitor);rectangle.accept(perimeterVisitor);}
}

总结

在这个例子中,访问者模式使我们能够为不同的图形元素定义不同的操作,而无需修改这些元素的代码。这种方式非常适合于需要对对象结构进行多次操作的情况。需要注意的是,如果对象结构发生变化,需要同时更新访问者的实现。

如果你还有其他问题或想深入了解某个方面,请随时告诉我!

示例2 文件系统

好的!我们可以考虑一个文件系统的示例,使用访问者模式来对不同类型的文件(如文本文件和图像文件)进行操作,例如计算文件大小和打印文件信息。

结构

  1. 文件接口(File):定义一个接受访问者的接口。
  2. 具体文件(TextFile, ImageFile):实现文件接口的类,表示不同类型的文件。
  3. 访问者接口(FileVisitor):定义访问方法。
  4. 具体访问者(SizeVisitor, PrintVisitor):实现访问者接口,定义对每种文件的操作。

示例代码

// 文件接口
interface File {void accept(FileVisitor visitor);
}// 具体文件:文本文件
class TextFile implements File {private String name;private int size;  // 单位:KBpublic TextFile(String name, int size) {this.name = name;this.size = size;}@Overridepublic void accept(FileVisitor visitor) {visitor.visit(this);}public String getName() {return name;}public int getSize() {return size;}
}// 具体文件:图像文件
class ImageFile implements File {private String name;private int size;  // 单位:KBpublic ImageFile(String name, int size) {this.name = name;this.size = size;}@Overridepublic void accept(FileVisitor visitor) {visitor.visit(this);}public String getName() {return name;}public int getSize() {return size;}
}// 访问者接口
interface FileVisitor {void visit(TextFile textFile);void visit(ImageFile imageFile);
}// 具体访问者:计算文件大小
class SizeVisitor implements FileVisitor {private int totalSize = 0;@Overridepublic void visit(TextFile textFile) {totalSize += textFile.getSize();}@Overridepublic void visit(ImageFile imageFile) {totalSize += imageFile.getSize();}public int getTotalSize() {return totalSize;}
}// 具体访问者:打印文件信息
class PrintVisitor implements FileVisitor {@Overridepublic void visit(TextFile textFile) {System.out.println("Text File: " + textFile.getName() + ", Size: " + textFile.getSize() + " KB");}@Overridepublic void visit(ImageFile imageFile) {System.out.println("Image File: " + imageFile.getName() + ", Size: " + imageFile.getSize() + " KB");}
}// 使用示例
public class Main {public static void main(String[] args) {File textFile = new TextFile("Document.txt", 15);File imageFile = new ImageFile("Picture.jpg", 200);// 计算文件大小SizeVisitor sizeVisitor = new SizeVisitor();textFile.accept(sizeVisitor);imageFile.accept(sizeVisitor);System.out.println("Total Size: " + sizeVisitor.getTotalSize() + " KB");// 打印文件信息PrintVisitor printVisitor = new PrintVisitor();textFile.accept(printVisitor);imageFile.accept(printVisitor);}
}

运行后输出的结果会是:

Total Size: 215 KB
Text File: Document.txt, Size: 15 KB
Image File: Picture.jpg, Size: 200 KB

解释:

  1. Total Size: 计算了所有文件的总大小(15 KB + 200 KB = 215 KB)。
  2. 打印文件信息: 显示了每个文件的名称和大小。

如果你还有其他问题或者想要更多示例,请告诉我!

总结

在这个例子中,访问者模式允许我们在不修改文件类的情况下,动态添加新的操作,如计算总文件大小和打印文件信息。这样可以在不同操作之间灵活切换,同时遵循开放/关闭原则。

如果你有其他问题或者需要进一步讨论,欢迎随时问我!


http://www.ppmy.cn/embedded/123325.html

相关文章

LabVIEW裂纹深度在线监测系统

随着铁路运输技术的快速发展,火车安全问题成为重中之重,尤其是轮面裂纹的检测和管理。裂纹的出现可能导致严重的列车事故,因此,建立可靠的在线监测系统,实时掌握裂纹情况,对保障铁路运输安全至关重要。 La…

昇思学习打卡营学习记录:CycleGAN壁画修复

按照提示,运行实训代码 进入实训平台:https://xihe.mindspore.cn/projects 选择“jupyter 在线编辑器” 启动“Ascend开发环境” :Ascend开发环境需要申请,大家可以申请试试看 启动开发环境后,在左边的文件夹中&am…

oracle 新建用户,用户插入数据报错:ORA-01950: 对表空间 ‘USERS‘ 无权限

oracle 新建用户,用户插入数据报错:ORA-01950: 对表空间 ‘USERS’ 无权限 根据业务需求创建了一个新的表空间和一个新的用户,当用这个新用户创建表时,报错:ORA-01950: 表空 间’USERS’中无权限。我已经把创建表的权限赋给了此用…

C++仿函数的介绍以及priority_queue的介绍和模拟实现

目录 1.仿函数 1.1仿函数的介绍 1.2自定义类型使用仿函数 1.3自定义支持比较大小,但是比较的逻辑不是自己想要的逻辑 2.优先级队列priority_queue 2.1priority_queue的介绍 2.2priority_queue的使用 2.3priority_queue的模拟实现 1.仿函数 1.1仿函数的介绍…

高级java每日一道面试题-2024年9月30日-服务器篇[Redis篇]-Redis持久化有几种方式?

如果有遗漏,评论区告诉我进行补充 面试官: Redis持久化有几种方式? 我回答: Redis 是一个高性能的键值存储系统,常用于缓存、消息队列和实时数据分析等场景。为了保证数据的持久性,Redis 提供了两种主要的持久化方式:RDB(Redi…

C#串口温度读取

背景:每天学点,坚持 要安装好虚拟串口和modbus poll,方便调试(相关资源在文末,也可以私信找我要) 传感器部分使用的是达林科技的DL11B-MC-D1,当时42软妹币买的(官网上面有这个传感…

k8s 之常用命令

作者:程序那点事儿 日期:2024/01/30 01:29 route route -n kubectl apply(不存在就创建,存在就更新,执行的文件较小) kubectl apply -f kube-flannel.yml kubectl apply -f nfs-storage-class.yaml ku…

力扣(leetcode)每日一题 2376 统计特殊整数 | 数位dp | 暴力递归+记忆化搜索

题干 2376. 统计特殊整数 如果一个正整数每一个数位都是 互不相同 的,我们称它是 特殊整数 。 给你一个 正 整数 n ,请你返回区间 [1, n] 之间特殊整数的数目。 示例 1: **输入:**n 20 **输出:**19 **解释&#…