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

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 二十三种设计模式全面解析-访问者模式的高级应用和实践技巧

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


访问者模式最重要的特性之一就是双重分发(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();
    }
}


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


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

相关文章
|
3天前
|
设计模式 存储 数据库连接
PHP中的设计模式:单例模式的深入理解与应用
【10月更文挑战第22天】 在软件开发中,设计模式是解决特定问题的通用解决方案。本文将通过通俗易懂的语言和实例,深入探讨PHP中单例模式的概念、实现方法及其在实际开发中的应用,帮助读者更好地理解和运用这一重要的设计模式。
7 1
|
6天前
|
设计模式 API 持续交付
深入理解微服务架构:设计模式与实践
【10月更文挑战第19天】介绍了微服务架构的核心概念、设计模式及最佳实践。文章详细探讨了微服务的独立性、轻量级通信和业务能力,并介绍了聚合器、链式和发布/订阅等设计模式。同时,文章还分享了实施微服务的最佳实践,如定义清晰的服务边界、使用API网关和服务发现机制,以及面临的挑战和职业心得。
|
16天前
|
设计模式 PHP 开发者
PHP中的设计模式:桥接模式的解析与应用
在软件开发的浩瀚海洋中,设计模式如同灯塔一般,为开发者们指引方向。本文将深入探讨PHP中的一种重要设计模式——桥接模式。桥接模式巧妙地将抽象与实现分离,通过封装一个抽象的接口,使得实现和抽象可以独立变化。本文将阐述桥接模式的定义、结构、优缺点及其应用场景,并通过具体的PHP示例代码展示如何在实际项目中灵活运用这一设计模式。让我们一起走进桥接模式的世界,感受它的魅力所在。
|
14天前
|
设计模式 测试技术 持续交付
架构视角下的NHibernate:设计模式与企业级应用考量
【10月更文挑战第13天】随着软件开发向更复杂、更大规模的应用转变,数据访问层的设计变得尤为重要。NHibernate作为一个成熟的对象关系映射(ORM)框架,为企业级.NET应用程序提供了强大的支持。本文旨在为有一定经验的开发者提供一个全面的指南,介绍如何在架构层面有效地使用NHibernate,并结合领域驱动设计(DDD)原则来构建既强大又易于维护的数据层。
31 2
|
9天前
|
设计模式 开发者 Python
Python编程中的设计模式应用与实践###
【10月更文挑战第18天】 本文深入探讨了Python编程中设计模式的应用与实践,通过简洁明了的语言和生动的实例,揭示了设计模式在提升代码可维护性、可扩展性和重用性方面的关键作用。文章首先概述了设计模式的基本概念和重要性,随后详细解析了几种常用的设计模式,如单例模式、工厂模式、观察者模式等,在Python中的具体实现方式,并通过对比分析,展示了设计模式如何优化代码结构,增强系统的灵活性和健壮性。此外,文章还提供了实用的建议和最佳实践,帮助读者在实际项目中有效运用设计模式。 ###
10 0
|
15天前
|
设计模式 算法 PHP
PHP中的设计模式:策略模式的深入解析与实践
【10月更文挑战第12天】 在软件开发的世界中,设计模式是解决常见问题的最佳实践。它们不是具体的代码,而是一种编码和设计经验的总结。在PHP开发中,合理运用设计模式可以极大地提高代码的可维护性、扩展性和复用性。本文将深入探讨策略模式(Strategy Pattern)的原理、实现方式及其在PHP中的应用。通过具体示例,我们将展示如何利用策略模式来解耦算法与对象,从而让代码更加灵活和易于管理。
14 0
|
15天前
|
设计模式 存储 安全
PHP中的设计模式:单例模式的深入解析与实践
在PHP开发中,设计模式是提高代码可维护性、扩展性和重用性的关键技术之一。本文将深入探讨单例模式(Singleton Pattern)的原理、实现方式及其在PHP中的应用,同时通过实例展示如何在具体的项目场景中有效利用单例模式来管理和组织对象,确保全局唯一性的实现和最佳实践。
|
2月前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。
|
2天前
|
设计模式 开发者 Python
Python编程中的设计模式:工厂方法模式###
本文深入浅出地探讨了Python编程中的一种重要设计模式——工厂方法模式。通过具体案例和代码示例,我们将了解工厂方法模式的定义、应用场景、实现步骤以及其优势与潜在缺点。无论你是Python新手还是有经验的开发者,都能从本文中获得关于如何在实际项目中有效应用工厂方法模式的启发。 ###
|
18天前
|
设计模式 Java Kotlin
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
本教程详细讲解Kotlin语法,适合希望深入了解Kotlin的开发者。对于快速学习Kotlin语法,推荐查看“简洁”系列教程。本文重点介绍了构建者模式在Kotlin中的应用与改良,包括如何使用具名可选参数简化复杂对象的创建过程,以及如何在初始化代码块中对参数进行约束和校验。
16 3

推荐镜像

更多