访问者模式简介

2023-09-13 09:36:23

概念

访问者模式(Visitor pattern)是一种行为型设计模式,它允许在不修改已有对象结构的情况下定义新操作。该模式将数据结构与操作分离,使得新增操作变得容易,并且可以在不同的数据结构上复用相同的操作。

特点

  1. 将操作封装到独立的访问者类中,使得添加新的操作变得简单。
  2. 可以对一个对象结构中的元素进行多种不同类型的遍历和处理。
  3. 访问者模式通过双重分派来实现动态绑定,即运行时根据具体元素类型调用对应访问者方法。

优点

  1. 增加新的具体访问者或元素类都比较容易扩展,符合开闭原则。
  2. 将相关行为集中到一个类中,提高代码可维护性和可读性。
  3. 具体元素类无需关心如何执行具体操作逻辑,只需要接受访问者并调用自身方法即可。

缺点

  1. 增加新元素会涉及所有具体访问者类进行修改,在存在大量元素和/或具体访问者时可能导致代码改动较大。
  2. 访问者模式增加了系统复杂度,并且可能降低运行效率。

适用场景

  1. 需要对一个复杂对象结构中的元素进行不同类型的操作,而又不希望这些操作污染元素类。
  2. 需要在运行时动态添加新的操作,且这些操作可能是不断变化的。
  3. 对象结构稳定,但经常需要定义新的操作。

实现方式

通过将访问者对象传递给元素类,在元素类内部根据具体访问者类型调用对应方法。此方式只有一次动态绑定。

实现原理:

  1. 定义访问者接口(Visitor):该接口声明了多个重载方法,每个方法对应一个具体元素类,并且传入具体元素对象作为参数。
  2. 定义具体访问者类(ConcreteVisitor):实现了访问者接口,在每个visit方法中根据传入的具体元素类型进行相应操作。
  3. 定义抽象元素类(Element):声明accept方法,用于接受访问者对象并调用其visit方法。
  4. 定义具体元素类(ElementAElementB):继承自抽象元素类,实现accept方法,在其中将自身作为参数调用访问者对象的visit方法。

实现代码:

interface Visitor {
    void visit(ElementA element);
    void visit(ElementB element);
}

class ConcreteVisitor implements Visitor {
    @Override
    public void visit(ElementA element) {
        // 对ElementA进行操作逻辑
        System.out.println("Visiting Element A");
    }

    @Override
    public void visit(ElementB element) {
        // 对ElementB进行操作逻辑
        System.out.println("Visiting Element B");
    }
}

abstract class Element {
    public abstract void accept(Visitor visitor);
}

class ElementA extends Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

class ElementB extends Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}
public class Main {

    public static void main(String[] args) {
        Element elementA = new ElementA();
        Element elementB = new ElementB();

        Visitor visitor = new ConcreteVisitor();

        elementA.accept(visitor); // 调用ElementA的accept方法,并传入visitor对象
        elementB.accept(visitor); // 调用ElementB的accept方法,并传入visitor对象
    }
}

存在问题:
单分派方式的实现原理相对简单,但它有一个明显的缺点:每次新增具体元素类时,都需要在访问者接口和具体访问者类中添加对应的visit方法。这样会导致具体访问者类和抽象元素类之间的耦合增加,当元素和操作数量庞大时,维护起来可能会比较困难。

另外,在单分派方式下,动态绑定只发生一次,即在调用accept方法时根据具体元素类型选择合适的visit方法。因此,在运行时无法根据不同操作类型再进行动态绑定。

更多推荐

如何写一份出色的毕业设计任务书

title:如何写一份出色的毕业设计任务书date:2023-09-20毕业设计任务书是每个毕业生必须面对的关键文档。它不仅是你完成毕业设计的路线图,还是导师评估你工作的依据。因此,撰写一份清晰、详细且具体的任务书至关重要。本文将向你介绍如何编写一份出色的毕业设计任务书。1.确定项目背景和目的任务书的第一部分应该解释你

Mysql优化习惯|建表规约丶SQL规约丶索引规约

今天看到一个mysql规范,说mysql里面的字符集utf8不是真正的utf8(很感兴趣就去搜索了一下);真正的utf8字符集在mysql里面叫utf8mb4.感兴趣的自己可以去看下这个链接MySQL中的utf8并不是真正的UTF-8编码!!_mysql是真正utf-8_I'msureok!的博客-CSDN博客言归正传

06-Redis缓存高可用集群

上一篇:05-Redis高可用集群之水平扩展1.集群方案比较哨兵模式在redis3.0以前的版本要实现集群一般是借助哨兵sentinel工具来监控master节点的状态,如果master节点异常,则会做主从切换,将某一台slave作为master,哨兵的配置略微复杂,并且性能和高可用性等各方面表现一般,特别是在主从切换

Rust : 与C多种交互尝试

rust调用C端的库函数,有很多方法,场景也有所不同。包括windows还是linux,内置库还是自定义库,还是三方库等等。一、rust调用其内置的C库这个很简单,直接把extern"C"引入即可:比如,在rust端main.rs中:usestd::os::raw::c_int;//f32usestd::os::raw

什么是函数式编程(functional programming)?在JavaScript中如何实现函数式编程的概念?

聚沙成塔·每天进步一点点⭐专栏简介⭐函数式编程(FunctionalProgramming)⭐纯函数(PureFunctions)⭐不可变性(Immutability)⭐高阶函数(Higher-OrderFunctions)⭐函数组合(FunctionComposition)⭐声明式编程(DeclarativeProg

第15篇ESP32 idf框架 wifi联网_WiFi AP模式_手机连接到esp32开发板

第1篇:Arduino与ESP32开发板的安装方法第2篇:ESP32helloword第一个程序示范点亮板载LED第3篇:vscode搭建esp32arduino开发环境第4篇:vscode+platformio搭建esp32arduino开发环境​​​​​​第5篇:doit_esp32_devkit_v1使用pmw呼

AI AIgents时代-(三.)AutoGPT和AgentGPT

前两篇讲解了Agent的原理和组件,这节我将给大家介绍两个agent项目,给出它们的工作原理和区别,并教大家亲手尝试使用Agents🎉🟢AutoGPT🤖️我们的老朋友,之前文章也专门写过。AutoGPT是一个由ToranRichards创建的流行开源项目,github有接近15万星🌟。它利用GPT4作为大脑,结

运用贪心算法实现卡牌游戏-2023年全国青少年信息素养大赛Python复赛真题精选

[导读]:超平老师计划推出《全国青少年信息素养大赛Python编程真题解析》50讲,这是超平老师解读Python编程挑战赛真题系列的第18讲。全国青少年信息素养大赛(原全国青少年电子信息智能创新大赛)是“世界机器人大会青少年机器人设计与信息素养大赛”赛事之一,由中国电子学会主办,包含很多赛项,大赛自2013年举办,已连

WebGIS开发教程:切片地图服务和动态地图服务的区别以及加载方式

arcgis发布切片地图服务arcgis发布动态地图服务切⽚地图服务和动态地图服务是两种常⻅的Web地图服务类型,它们有以下⼏点区别:1.数据格式:切⽚地图服务是⼀种基于瓦⽚(Tile)数据的地图服务,地图数据被预先切成⼩块并存储在服务器上,⽤户在使⽤时只需加载需要的瓦⽚数据即可;⽽动态地图服务则是⼀种基于⽮量(Vec

面试(架构,网络)

java八股treemap和linkdedhashmap区别,实现原理https://blog.csdn.net/shidebin/article/details/126814905架构https://www.cnblogs.com/crazymakercircle/p/17197091.htmlhttps://www

免费和开源的机器翻译软件LibreTranslate

什么是LibreTranslate?LibreTranslate免费开源机器翻译API,完全自托管。与其他API不同,它不依赖于Google或Azure等专有提供商来执行翻译。它的翻译引擎由开源ArgosTranslate库提供支持。这个软件在2022年3月的时候折腾过,但当时容器会停止,从下面的文章看,应该可能是内存

热文推荐