23 种设计模式中的访问者模式

主要用于在不改变对象结构的前提下,为对象结构中的元素添加新的操作。

访问者模式用于解决稳定数据结构和易变操作之间的耦合问题,设计的目的是不改变数据结构的定义,但允许增加新的访问者,来定义新的操作。

这里我们根据案例来具体学习访问者模式。以下是一个代码示例及知识点详解:

首先,我们要定义一个访问者接口:

csharp 复制代码
// 1. 定义元素接口(被访问对象)
interface DocumentElement {
    void accept(DocumentVisitor visitor); // 接受访问者的方法
}

接下来,我们需要创建具体的元素类:

typescript 复制代码
// 2. 创建具体元素类
// 第一个元素类
class TextElement implements DocumentElement {
    private String content;
​
    public TextElement(String content) {
        this.content = content;
    }
​
    @Override
    public void accept(DocumentVisitor visitor) {
        visitor.visit(this); // 双分派关键点
    }
​
    public String getContent() { return content; }
}
typescript 复制代码
// 第二个元素类
class ImageElement implements DocumentElement {
    private String src;
​
    public ImageElement(String src) {
        this.src = src;
    }
​
    @Override
    public void accept(DocumentVisitor visitor) {
        visitor.visit(this);
    }
​
    public String getSrc() { return src; }
}

接着,我们要定义访问者接口,即该访问者能够干的事情:

arduino 复制代码
// 3. 定义访问者接口
interface DocumentVisitor {
    void visit(TextElement text);  // 重载方法处理不同元素
    void visit(ImageElement image);
}

然后,我们来实现具体的访问者:

typescript 复制代码
// 4. 实现具体访问者
class HTMLExportVisitor implements DocumentVisitor {
    @Override
    public void visit(TextElement text) {
        System.out.println("<p>" + text.getContent() + "</p>");
    }
​
    @Override
    public void visit(ImageElement image) {
        System.out.println("<img src="" + image.getSrc() + ""/>");
    }
}
typescript 复制代码
class MarkdownExportVisitor implements DocumentVisitor {
    @Override
    public void visit(TextElement text) {
        System.out.println(text.getContent() + "\n");
    }
​
    @Override
    public void visit(ImageElement image) {
        System.out.println("![](" + image.getSrc() + ")");
    }
}

紧接着,我们要定义一个能够持有被访问元素的数据结构

typescript 复制代码
// 5. 对象结构(管理元素集合)
class Document {
    private List<DocumentElement> elements = new ArrayList<>();
​
    public void addElement(DocumentElement e) {
        elements.add(e);
    }
​
    public void accept(DocumentVisitor visitor) {
        for (DocumentElement e : elements) {
            e.accept(visitor); // 触发访问操作
        }
    }
}

最后,测试下上述代码,看看客户端的执行效果:

typescript 复制代码
// 客户端使用
public class VisitorDemo {
    public static void main(String[] args) {
        Document doc = new Document();
        doc.addElement(new TextElement("Hello Visitor Pattern"));
        doc.addElement(new ImageElement("diagram.jpg"));
​
        // 不同访问者实现不同处理
        doc.accept(new HTMLExportVisitor());
        doc.accept(new MarkdownExportVisitor());
    }
}

由此可见,访问者模式的核心思想是为了访问比较复杂的数据结构,不改变数据结构。而是把对数据的访问方式抽象出来,在访问数据的过程中以回调形式在访问者中处理操作逻辑。

如果要新增一组操作,只需要新增一个访问者。

总结

访问者模式是为了抽象出一组作用于复杂对象的操作,并且后续可以新增操作而不需要对现有的数据结构做出改动。

相关推荐
Cosolar1 分钟前
下一代 Python Web 框架?FastAPI 全面解析与实战对比
后端·python
用户4822137167751 小时前
C++——复合数据类型(数组、字符串)
后端
用户903700167151 小时前
分布式阻塞式限流学习及分享
后端
熊猫片沃子1 小时前
Mybatis中进行批量修改的方法
java·后端·mybatis
养鱼的程序员1 小时前
零基础搭建个人网站:从 Astro 框架到 GitHub 自动部署完全指南
前端·后端·github
白应穷奇1 小时前
编写高性能数据处理代码 01
后端·python
杨充1 小时前
03.接口vs抽象类比较
前端·后端
一只叫煤球的猫2 小时前
基于Redisson的高性能延迟队列架构设计与实现
java·redis·后端
卡尓2 小时前
使用 Layui 替换 Yii 基础模板的默认 Bootstrap 样式并尝试重写导航栏组件
后端
WhyWhatHow2 小时前
JEnv:新一代Java环境管理器,让多版本Java管理变得简单高效
java·后端