【设计模式-访问者模式】

news/2024/9/29 8:11:36/

定义

访问者模式(Visitor Pattern)是一种行为型设计模式,允许你在不修改已有类的情况下向这些类添加新的功能或行为。它通过将操作的执行逻辑从对象的类中分离出来,使得你可以在保持类的封闭性(符合开闭原则)的前提下为不同对象定义新的操作。

UML图

在这里插入图片描述

  • Visitor(访问者):定义了针对元素结构中每种类型元素的访问操作,通常通过重载 visit 方法实现。
  • Element(元素接口或抽象类):定义了一个 accept(Visitor visitor) 方法,允许访问者访问自己。
  • ConcreteElement(具体元素):实现了 Element 接口,并在 accept 方法中调用访问者的对应方法,如 visitor.visit(this)。
  • ConcreteVisitor(对象结构):可以是一个包含不同类型元素的集合,它负责遍历元素并对每个元素调用 accept 方法。

优点

  • 开闭原则:可以在不修改现有类的情况下添加新的操作。
  • 单一职责原则:通过将元素的操作行为封装到访问者中,元素类的职责得以简化。
  • 可扩展性强:可以为对象结构中的类定义新的操作,而不改变类的定义。

缺点

  • 破坏封装性:访问者需要了解元素的内部细节,这可能破坏类的封装性。
  • 难以维护:如果元素类频繁变更,则需要更新所有访问者,访问者模式的维护成本可能较高。
  • 双重分派问题访问者模式的实现涉及双重分派,即通过 accept 方法调用访问者的 visit 方法,这使得结构变得复杂。

代码

// 定义访问者接口
interface Visitor {void visit(Book book);void visit(Fruit fruit);
}// 定义元素接口
interface ItemElement {void accept(Visitor visitor);
}// 具体元素类 Book
class Book implements ItemElement {private String title;private double price;public Book(String title, double price) {this.title = title;this.price = price;}public String getTitle() {return title;}public double getPrice() {return price;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}// 具体元素类 Fruit
class Fruit implements ItemElement {private String name;private double weight;private double pricePerKg;public Fruit(String name, double weight, double pricePerKg) {this.name = name;this.weight = weight;this.pricePerKg = pricePerKg;}public String getName() {return name;}public double getWeight() {return weight;}public double getPricePerKg() {return pricePerKg;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}// 实现具体的访问者
class ShoppingCartVisitor implements Visitor {@Overridepublic void visit(Book book) {System.out.println("Book: " + book.getTitle() + ", Price: " + book.getPrice());}@Overridepublic void visit(Fruit fruit) {double cost = fruit.getWeight() * fruit.getPricePerKg();System.out.println("Fruit: " + fruit.getName() + ", Cost: " + cost);}
}// 测试访问者模式
public class VisitorPatternDemo {public static void main(String[] args) {ItemElement[] items = new ItemElement[] {new Book("Design Patterns", 50),new Fruit("Apple", 2, 3)};Visitor visitor = new ShoppingCartVisitor();for (ItemElement item : items) {item.accept(visitor); // 访问每个元素}}
}

场景

  • 对象结构稳定:当你的对象结构(类)相对固定,但需要在这个结构上添加新的操作时,访问者模式非常合适。这样可以避免修改已有类的代码。
  • 需要对多个类执行相似的操作:当你需要对多个不同类型的元素执行类似的操作时,使用访问者模式可以集中管理这些操作。
  • 复杂的对象结构:在处理复杂的对象结构时(例如树形结构),访问者模式可以提供清晰的访问逻辑,避免在每个元素中实现相同的逻辑。
  • 数据结构和操作分离:当你希望将数据结构与操作分离,以便于未来扩展时,访问者模式是一个良好的选择。这样可以保持类的单一职责原则。
  • 频繁变化的操作:如果你的操作逻辑频繁变化,但元素结构相对稳定,使用访问者模式可以方便地添加新的操作而不影响已有的元素类。
  • 需要对元素进行类型判断访问者模式允许在访问者中根据元素的具体类型执行不同的操作,便于类型判断和特定处理。

具体示例

  • 编译器:在编译器中,抽象语法树(AST)需要执行不同的操作(如语义分析、优化等),访问者模式可以有效地管理这些操作。
  • 图形绘制:在图形编辑软件中,图形元素(如线条、圆形、矩形等)可以通过访问者模式实现不同的绘制和变换操作。
  • 文件系统:在文件系统中,可以定义访问者来实现文件的不同处理(如压缩、加密等),而不需要修改文件类的实现。
  • 账单处理:在购物车或账单系统中,可以使用访问者模式来处理不同类型的商品(如书籍、食品等),并计算总价或应用折扣。

总结

访问者模式适合于需要在多个元素上执行不同操作,且希望保持代码清晰和可扩展的情况。


http://www.ppmy.cn/news/1531837.html

相关文章

【单元测试】任务1:白盒测试1

1. 任务前置知识 2. 任务周期安排 3. 任务参考文档 4. 任务实现要求 4.1.白盒测试—逻辑覆盖—语句覆盖 4.2.白盒测试—逻辑覆盖—判定覆盖 4.3.白盒测试—逻辑覆盖—条件覆盖 需要技能竞赛软件测试资料的同学们可s聊我,详细了解 1. 任务前置知识 Java程序设…

基于php的助农生鲜销售系统

作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏:Java精选实战项目…

美畅物联丨GB/T 28181系列之TCP/UDP被动模式和TCP主动模式

GB/T 28181《安全防范视频监控联网系统信息传输、交换、控制技术要求》作为我国安防领域的重要标准,为视频监控系统的建设提供了全面的技术指导和规范。该标准详细规定了视频监控系统的信息传输、交换和控制技术要求,在视频流传输方面,GB/T 2…

初探shell与bash使用指南

文章目录 一、shell二、bash第一步、新建脚本第二步、添加权限第三步、执行bash脚本 在日常开发中,经常使用到Linux服务器相关知识,输入命令获取想要的结果,本篇介绍shell 与 bash的相关知识。 一、shell 是命令行解释器,接收用户…

深度学习(4):torch.nn.Module

文章目录 一、是什么二、nn.Module 的核心功能三、nn.Module 的基本用法1. 定义自定义模型2. 初始化模型3. 模型的使用 四、nn.Module 的关键特性1. 自动注册子模块和参数2. forward 方法3. 不需要定义反向传播 五、常用的内置模块六、示例:创建一个简单的神经网络1…

基于微信开发助手企鹅音乐微信小程序的设计与实现(源码+文档+讲解)

博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…

docker - 镜像操作(拉取、查看、删除)

文章目录 1、docker search --help(用于显示 Docker 搜索命令的帮助信息)2、docker pull(拉取镜像)3、docker images (查看镜像)3.1、docker images --help(用于显示 Docker 镜像管理相关命令的帮助信息)3.…

前端面试经验总结2(经典问题篇)

谈谈你对前端的理解 前端主要负责产品页面部分的实现,是最贴近于用户的程序员。 基本工作要求: 1.参与项目,通过与团队成员,UI设计,产品经理的沟通,快速高质量的实现效果图,并能够精确到1px 2.做…