二十三种设计模式全面解析-访问者模式的高级应用和实践技巧

简介: 二十三种设计模式全面解析-访问者模式的高级应用和实践技巧

通过前文的介绍,我们已经对访问者模式有了一定的了解,并在简单示例中看到了它的基本应用。然而,访问者模式还有许多高级应用和实践技巧,让我们继续深入探索。


访问者模式最重要的特性之一就是双重分发(double dispatch)。在前面的示例中,我们通过元素的 accept 方法将访问者对象传递给元素,然后由元素调用访问者的 visit 方法。这种方式实现了根据元素的类型来决定调用哪个具体的访问者方法,从而实现了双重分发。


双重分发使得我们可以在运行时根据元素的类型和访问者的类型来决定执行的操作,而不是在编译时就确定。这种灵活性使得我们可以根据需要动态地添加新的元素类型和访问者类型,而不需要修改现有的代码。


当访问者模式与双重分发和其他设计模式结合使用时,可以实现更加灵活和强大的解决方案。让我们通过一个详细的案例代码来说明这些应用。


案例场景:

假设我们正在开发一个图形编辑器,其中包含多种图形元素,如圆形、矩形和三角形。我们希望能够对这些图形元素进行不同的操作,如绘制、移动、缩放等。同时,我们还希望能够实现撤销(Undo)和重做(Redo)的功能。为了实现这些需求,我们将访问者模式与双重分发和命令模式相结合使用。


  1. 双重分发的应用:
    首先,我们定义访问者接口 Visitor 和图形元素接口 Shape
// 访问者接口
interface Visitor {
    void visit(Circle circle);
    void visit(Rectangle rectangle);
    void visit(Triangle triangle);
}
// 图形元素接口
interface Shape {
    void accept(Visitor visitor);
}


然后,实现具体的图形元素类,分别是 CircleRectangleTriangle

// 圆形类
class Circle implements Shape {
    private int radius;
    public Circle(int radius) {
        this.radius = radius;
    }
    public int getRadius() {
        return radius;
    }
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}
// 矩形类
class Rectangle implements Shape {
    private int width;
    private int height;
    public Rectangle(int width, int height) {
        this.width = width;
        this.height = height;
    }
    public int getWidth() {
        return width;
    }
    public int getHeight() {
        return height;
    }
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}
// 三角形类
class Triangle implements Shape {
    private int base;
    private int height;
    public Triangle(int base, int height) {
        this.base = base;
        this.height = height;
    }
    public int getBase() {
        return base;
    }
    public int getHeight() {
        return height;
    }
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}


接下来,我们实现具体的访问者类 DrawingVisitor,用于绘制图形元素:

// 绘制访问者
class DrawingVisitor implements Visitor {
    @Override
    public void visit(Circle circle) {
        System.out.println("绘制圆形,半径:" + circle.getRadius());
    }
    @Override
    public void visit(Rectangle rectangle) {
        System.out.println("绘制矩形,宽度:" + rectangle.getWidth() + ",高度:" + rectangle.getHeight());
    }
    @Override
    public void visit(Triangle triangle) {
        System.out.println("绘制三角形,底边:" + triangle.getBase() + ",高度:" + triangle.getHeight());
    }
}


现在,我们可以创建图形元素并让绘制访问者对其进行操作:

public class Client {
    public static void main(String[] args) {
        Shape circle = new Circle(5);
        Shape rectangle = new Rectangle(10, 20);
        Shape triangle = new Triangle(8, 12);
        Visitor drawingVisitor = new DrawingVisitor();
        circle.accept(drawingVisitor);
        rectangle.accept(drawingVisitor);
        triangle.accept(drawingVisitor);
    }
}

输出结果:

绘制圆形,半径:5
绘制矩形,宽度:10,高度:20
绘制三角形,底边:8,高度:12


通过双重分发,我们可以根据具体的图形元素类型调用相应的访问者方法,实现了根据元素类型来决定执行的操作。


2、访问者模式与其他模式的结合:

在上述案例中,我们还将访问者模式与命令模式相结合,以实现撤销和重做功能。我们定义了两个命令接口 CommandUndoableCommand,并实现了具体的命令类 DrawCommandMoveCommand

// 命令接口
interface Command {
    void execute();
}
// 可撤销的命令接口
interface UndoableCommand extends Command {
    void undo();
}
// 绘制命令类
class DrawCommand implements UndoableCommand {
    private Shape shape;
    public DrawCommand(Shape shape) {
        this.shape = shape;
    }
    @Override
    public void execute() {
        shape.accept(new DrawingVisitor());
    }
    @Override
    public void undo() {
        // 撤销绘制操作
    }
}
// 移动命令类
class MoveCommand implements UndoableCommand {
    private Shape shape;
    private int deltaX;
    private int deltaY;
    public MoveCommand(Shape shape, int deltaX, int deltaY) {
        this.shape = shape;
        this.deltaX = deltaX;
        this.deltaY = deltaY;
    }
    @Override
    public void execute() {
        // 移动图形元素
    }
    @Override
    public void undo() {
        // 撤销移动操作
    }
}


此外,我们还定义了一个命令历史记录类 CommandHistory,用于管理命令的执行和撤销:

import java.util.Stack;
// 命令历史记录类
class CommandHistory {
    private Stack<UndoableCommand> undoStack;
    public CommandHistory() {
        undoStack = new Stack<>();
    }
    public void executeCommand(UndoableCommand command) {
        command.execute();
        undoStack.push(command);
    }
    public void undo() {
        if (!undoStack.isEmpty()) {
            UndoableCommand command = undoStack.pop();
            command.undo();
        }
    }
}


现在,我们可以通过命令模式来执行绘制和移动操作,并实现撤销和重做的功能:

public class Client {
    public static void main(String[] args) {
        Shape circle = new Circle(5);
        Shape rectangle = new Rectangle(10, 20);
        Shape triangle = new Triangle(8, 12);
        UndoableCommand drawCircleCommand = new DrawCommand(circle);
        UndoableCommand drawRectangleCommand = new DrawCommand(rectangle);
        UndoableCommand drawTriangleCommand = new DrawCommand(triangle);
        UndoableCommand moveRectangleCommand = new MoveCommand(rectangle, 5, 10);
        CommandHistory commandHistory = new CommandHistory();
        // 执行绘制命令
        commandHistory.executeCommand(drawCircleCommand);
        commandHistory.executeCommand(drawRectangleCommand);
        commandHistory.executeCommand(drawTriangleCommand);
        // 执行移动命令
        commandHistory.executeCommand(moveRectangleCommand);
        // 撤销最后一个命令
        commandHistory.undo();
    }
}


通过将访问者模式与双重分发和命令模式相结合,我们实现了对图形元素的绘制和移动操作,并且可以撤销和重做这些操作。这种组合使用的方式可以在复杂的应用场景中提供更大的灵活性和可扩展性,使代码结构更清晰、可维护性更高。


好了,今天的分享到此结束。

相关文章
|
7月前
|
设计模式 XML JSON
【设计模式】【行为型模式】访问者模式(Visitor)
一、入门 什么是访问者模式? 访问者模式(Visitor Pattern)是一种行为设计模式,允许你将算法与对象结构分离。通过这种方式,可以在不改变对象结构的情况下,向对象结构中的元素添加新的操作。
225 10
|
9月前
|
人工智能 API 语音技术
HarmonyOS Next~鸿蒙AI功能开发:Core Speech Kit与Core Vision Kit的技术解析与实践
本文深入解析鸿蒙操作系统(HarmonyOS)中的Core Speech Kit与Core Vision Kit,探讨其在AI功能开发中的核心能力与实践方法。Core Speech Kit聚焦语音交互,提供语音识别、合成等功能,支持多场景应用;Core Vision Kit专注视觉处理,涵盖人脸检测、OCR等技术。文章还分析了两者的协同应用及生态发展趋势,展望未来AI技术与鸿蒙系统结合带来的智能交互新阶段。
560 31
|
9月前
|
设计模式 SQL Java
【再谈设计模式】解释器模式~语法的解析执行者
解释器模式定义了一种语言的语法表示,并定义一个解释器来解释该语言中的句子。它使用类来表示每个语法规则,并且通过递归调用这些类的方法来解释表达式。本质上,它将一个复杂的表达式分解为一系列简单的部分,然后按照特定的语法规则进行解析和执行。
237 8
|
9月前
|
缓存 边缘计算 安全
阿里云CDN:全球加速网络的实践创新与价值解析
在数字化浪潮下,用户体验成为企业竞争力的核心。阿里云CDN凭借技术创新与全球化布局,提供高效稳定的加速解决方案。其三层优化体系(智能调度、缓存策略、安全防护)确保低延迟和高命中率,覆盖2800+全球节点,支持电商、教育、游戏等行业,帮助企业节省带宽成本,提升加载速度和安全性。未来,阿里云CDN将继续引领内容分发的行业标准。
502 7
|
9月前
|
机器学习/深度学习 人工智能 自然语言处理
DeepSeek 实践应用解析:合力亿捷智能客服迈向 “真智能” 时代
DeepSeek作为人工智能领域的创新翘楚,凭借领先的技术实力,在智能客服领域掀起变革。通过全渠道智能辅助、精准对话管理、多语言交互、智能工单处理、个性化推荐、情绪分析及反馈监控等功能,大幅提升客户服务效率和质量,助力企业实现卓越升级,推动智能化服务发展。
374 1
|
9月前
|
机器学习/深度学习 人工智能 监控
鸿蒙赋能智慧物流:AI类目标签技术深度解析与实践
在数字化浪潮下,物流行业面临变革,传统模式的局限性凸显。AI技术为物流转型升级注入动力。本文聚焦HarmonyOS NEXT API 12及以上版本,探讨如何利用AI类目标签技术提升智慧物流效率、准确性和成本控制。通过高效数据处理、实时监控和动态调整,AI技术显著优于传统方式。鸿蒙系统的分布式软总线技术和隐私保护机制为智慧物流提供了坚实基础。从仓储管理到运输监控再到配送优化,AI类目标签技术助力物流全流程智能化,提高客户满意度并降低成本。开发者可借助深度学习框架和鸿蒙系统特性,开发创新应用,推动物流行业智能化升级。
292 1
|
9月前
|
存储 自然语言处理 监控
深度解析淘宝商品评论API接口:技术实现与应用实践
淘宝商品评论API接口是电商数据驱动的核心工具,帮助开发者高效获取用户评价、画像及市场趋势。其核心功能包括多维度信息采集、筛选排序、动态更新、OAuth 2.0认证和兼容多种请求方式。通过该接口,开发者可进行商品优化、竞品分析、舆情监控等。本文详细解析其技术原理、实战应用及挑战应对策略,助力开启数据驱动的电商运营新篇章。
|
9月前
|
算法 测试技术 C语言
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
846 29
|
9月前
|
前端开发 数据安全/隐私保护 CDN
二次元聚合短视频解析去水印系统源码
二次元聚合短视频解析去水印系统源码
344 4
|
9月前
|
JavaScript 算法 前端开发
JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)
这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~

热门文章

最新文章

推荐镜像

更多
  • DNS