设计模式(18)行为型模式 - 访问者模式

前言

温故而知新

还是先复习前面学到的知识:

  • 行为型模式:描述多个类或对象之间怎么协助共同完成单个对象无法实现的任务,涉及算法与对象间的职责分配

  • 模板方法模式:定义一个操作流程中的算法骨架,特定的步骤方法的具体实现延迟到子类,即方便与重定义一个算法的特定步骤(请客过程具体吃什么有子类决定,父类只定义一个请客流程:点单 - 》 吃饭 - 》买单)

  • 命令模式:将请求命令封装成对象,并将执行者聚合到命令中,发送者维护一个保存命令的容器,调用发送者去使用命令对象即可完成命令,使得命令发送者和命令执行者完全解耦(点击遥控器上的命令按键即可完成具体开关灯–遥控器并不知道如何执行,只管发送命令)

接下来,是一个比较复杂抽象而且使用也较少的设计模式:访问者模式


现实中存在的问题

购物车的问题:
在这里插入图片描述
顾客在超市中将选择的商品,如苹果、图书等放在购物车中,然后到收银员处付款。
在购物过程中,顾客需要对这些商品进行访问,以便确认这些商品的质量。
收银员计算价格时也需要访问购物车内顾客所选择的商品。

此时,购物车作为一个ObjectStructure(对象结构)用于存储各种类型的商品,而顾客和收银员作为访问这些商品的访问者,他们需要对商品进行检查和计价。

不同类型的商品其访问形式也可能不同,如苹果需要过秤之后再计价,而图书不需要。

这个场景,可以思考一下什么去描述?

学习过程中,掌握主动性,学会提问,让疑问带领着去学习

用传统方法,会创建对象:苹果、图书、顾客、收银员、购物车,然后互相调用方法???
传统方法可以解决,但是要是又增加了商品:可乐,需要修改很多类

学了这节访问者模式,会有很好的解决方案


访问者模式

先大致了解一下访问者模式的概念,再经过案例分析

访问者模式(Visitor Pattern):表示一个作用于某对象结构中的各元素的操作,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式是一种对象行为型模式

访问者模式的目的是封装一些施加于某种对象结构的元素之上的操作,一旦这些操作需要修改的话,接受这个操作的对象结构可以保持不变。为不同类型的元素提供多种访问操作方式,且可以在不修改原有系统的情况下增加新的操作方式

模式结构:
在这里插入图片描述

模式角色:

  • 抽象访问者(Visitor)角色:定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作 visit(),该操作中的参数类型标识了被访问的具体元素。
  • 具体访问者(ConcreteVisitor)角色:实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么。
  • 抽象元素(Element)角色:声明一个包含接受操作 accept() 的接口,被接受的访问者对象作为 accept() 方法的参数。
  • 具体元素(ConcreteElement)角色:实现抽象元素角色提供的 accept() 操作,其方法体通常都是visitor.visit(this) ,另外具体元素中可能还包含本身业务逻辑的相关操作。
  • 对象结构(Object Structure)角色:是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由List、Set、Map 等聚合类实现

模式分析

  • 访问者模式中对象结构角色存储了不同类型的元素对象,以供不同访问者访问。
  • 访问者模式包括两个层次结构,一个是访问者层次结构,提供了抽象访问者和具体访问者,一个是元素层次结构,提供了抽象元素和具体元素。
  • 相同的访问者可以以不同的方式访问不同的元素,相同的元素可以接受不同访问者以不同访问方式访问。在访问者模式中,增加新的访问者无须修改原有系统,系统具有较好的可扩展性

模式案例

用访问者模式实现上面说的购物车案例

简单实现:

在这里插入图片描述

package com.company.Behavioral.visitor;import java.util.ArrayList;
import java.util.List;
//抽象访问者
abstract class Visitor {public abstract void visit(Apple apple);public abstract void visit(Book book);
}
//具体访问者:顾客
class Customer extends Visitor{@Overridepublic void visit(Apple apple) {System.out.println("-----查看苹果质量----");}@Overridepublic void visit(Book book) {System.out.println("-----查看书的名字-----");}
}
//具体
class Cashier extends Visitor{@Overridepublic void visit(Apple apple) {System.out.println(" 查看苹果的价钱。。。");}@Overridepublic void visit(Book book) {System.out.println(" 查看书本的价钱。。。");}
}
//抽象产品
abstract class Product {public abstract void accept(Visitor visitor);
}
//用到了双分派:在后面的程序中具体的访问者作为参数传递到Apple(第一次分派)
//Apple类调用了作为参数的“具体访问者”中的方法visit,同时将自己(this)作为参数传入,完成第二次的分派
class Apple extends Product{@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}
class Book extends Product{@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}
//数据结构,管理了很多产品(Customer,Woman)
class ShoppingCart{//维护一个集合private List<Product> products = new ArrayList<>();//增加到集合public void attach(Product p){products.add(p);}//从集合移除public void detach(Product p){products.remove(p);}//访问者访问购物车的情况public void display(Visitor visitor){for (Product p : products){p.accept(visitor);}}
}class Client{public static void main(String[] args) {//创建ShoppingCartShoppingCart shoppingCart = new ShoppingCart();shoppingCart.attach(new Apple());shoppingCart.attach(new Apple());shoppingCart.attach(new Book());//顾客查看购物车Customer customer = new Customer();shoppingCart.display(customer);//收银员查看购物车Cashier cashier = new Cashier();shoppingCart.display(cashier);}
}

在这里插入图片描述

访问者模式可以使我们在不改变元素(具体的产品)的情况下,定义一下作用于这些产品的新操作(新的访问者)

如果我们创建一个新的访问者:调查者,调查者任务是调查顾客购物的类型
只需要新建一个具体访问者继承访问者接口即可


访问者模式的优缺点

优点

  • 使得增加新的访问操作变得很容易
  • 将有关元素对象的访问行为集中到一个访问者对象中,而不是分散到一个个的元素类中
  • 可以跨过类的等级结构访问属于不同的等级结构的元素类
  • 让用户能够在不修改现有类层次结构的情况下,定义该类层次结构的操作

缺点

仔细想想,其实上面的购物车例子有点问题。。。
因为访问的物品类型已经在访问者类中写死了,造成

  • 增加新的元素类很困难。在访问者模式中,每增加一个新的元素类都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作,违背了“开闭原则”的要求。
  • 破坏封装。访问者模式要求访问者对象访问并调用每一个元素对象的操作,这意味着元素对象有时候必须暴露一些自己的内部操作和内部状态,否则无法供访问者访问

从这个缺点看出,访问者模式应该是使用在元素类种类稳定的系统中


适用场景

  • 一个对象结构包含很多类型的对象,希望对这些对象实施一些依赖其具体类型的操作。在访问者中针对每一种具体的类型都提供了一个访问操作,不同类型的对象可以有不同的访问操作
  • 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作“污染”这些对象的类,也不希望在增加新操作时修改这些类。访问者模式使得我们可以将相关的访问操作集中起来定义在访问者类中,对象结构可以被多个不同的访问者类所使用,将对象本身与对象的访问操作分离。
  • 对象结构中元素对应的类很少改变,但经常需要在此对象结构上定义新的操作

具体中的使用

  1. Java XML处理技术DOM4J中,可以通过访问者模式的方式来读取并解析XML文档,VisitorSupport是DOM4J提供的Visitor接口的默认适配器,具体访问者只需继承VisitorSupport类即可

什么?不知道DOM4J?可以看看真的了解XML吗? - XML解析方式

DOM4J解析XML利用访问者(VisitorSupport)解析XML文件。通过重写各种类型的visit()方法解析各种节点,文本内容

具体使用:

//解析器
SAXReader saxReader = new SAXReader();
//解析具体的xml文件
Document doc = saxReader.read(new File("book.xml"));
//Visitor是自定义的访问者,里面重写了VisitorSupport的visit方法
doc.accept(new Visitor());
class Visitor extends VisitorSupport{@Overridepublic void visit(Attribute node){//自定义访问结点Attribute的操作}@Overridepublic void visit(Element node){//自定义访问结点Element操作}
}
  1. 编译器的设计

程序代码是被访问的对象,它包括变量定义、变量赋值、逻辑运算、算术运算等语句,编译器需要对代码进行分析

可以将不同的操作封装在不同的类中,如检查变量定义的类、检查变量赋值的类、检查算术运算是否合法的类,这些类就是具体访问者,可以访问程序代码中不同类型的语句

可以将每一个不同编译阶段的操作封装到了跟该阶段有关的一个访问者类中


模式扩展

访问者模式同“组合模式”联用

访问者模式中的“元素对象”可能是叶子对象或者是容器对象,如果元素对象包含容器对象,就必须用到组合模式
在这里插入图片描述

这样联用已经比较复杂了

访问者模式与迭代器模式联用

我们的访问者的对象结构类中维护了一个元素对象的集合,因此访问者模式经常需要与迭代器模式联用,在对象结构中使用迭代器来遍历元素对象(案例中使用for-each循环遍历也是用到了迭代器)

“开闭原则”倾斜

访问者模式以一种倾斜的方式支持“开闭原则”,增加新的访问者方便,但是增加新的元素很困难

还记得前面也有一个“开闭原则”倾斜:抽象工厂模式
抽象工厂模式中增加产品族很简单,增加产品等级很困难

这是因为,我们必须在一个对象结构(抽象工厂)写死完整的体系,只能做到针对一个方面,所以选择设计模式是需要根据实际情况抉择


总结

  • 访问者模式是封装一些施加与对象结构上的元素的操作,即将访问者隔离开这个对象结构,当新增访问操作时并不会改动这个对象结构
  • 访问者模式的结构有5个角色:抽象访问者、具体访问者、抽象元素角色、具体元素角色、对象结构角色
  • 访问者拥有访问所有的元素的操作;元素角色拥有接收访问者操作的接口;对象结构角色维护了一个存储元素角色的集合,并提供给访问者遍历元素角色的方法
  • 访问者模式的优点是新增访问者(访问操作)方便,在不修改对象结构的情况下可以新增对元素的访问;缺点是新增元素角色困难,一定程度会破坏系统的封装性
  • 访问者模式适用场景:一个对象结构包含很多类型的对象,希望对这些对象实施一些依赖其具体类型的操作;需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作“污染”这些对象的类,也不希望在增加新操作时修改这些类;对象结构中元素对应的类很少改变,但经常需要在此对象结构上定义新的操作
  • 访问者模式可以和组合模式联用,即元素对象可以有叶子元素对象、容器元素对象;访问者模式可以和迭代器模式联用,即对象结构中的元素使用迭代器遍历

访问者模式开闭原则倾斜,使用时需要根据实际情况选择

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/29728.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

诚之和:滴滴禁闭百日司机、用户与暗战

撰文 吴先之 编辑 | 王 潘 西非的黑猩猩既聪明又残忍。 每当旧王年老体衰时,其他猩猩会将它围殴致死然后分而食之,这么做的目的不仅仅是发泄积压已久的愤怒,还希望继承一部分“王者之气”。 7月2日监管部门开始对滴滴进行审查,暂停新用户注册、下架APP等接踵而至。巨头…

LiteOS学习---开发环境初识

背景介绍 记得电影《一代宗师中》&#xff0c;有这样一句话 也是时势使然&#xff0c;某为厂成了面子&#xff0c;欺负它就等于打了国人的脸&#xff0c;至于它担不担得起&#xff0c;另说。 早在2015年&#xff0c;华为就推出了这个LiteOS。如果问它和鸿蒙系统有什么关系 华…

第 6 篇、Linux C基础 | 数据类型和标识符

1.C语言的数据类型 001基本类型 字符类型&#xff1a; char 1 byte 8 bit 1111 1111 1-----------最高位符号位&#xff0c;1 负 0 正 unsigned char 无符号的字符类型 signed char 有符号的char类型 整型&#xff1a; 短整型&#xff1a;short 2 byt…

暗影精灵3等游戏本设置风扇静音

很多游戏本的风扇声音很大&#xff0c;即使仅使用word进行码字有时风扇的速度也限制不住&#xff0c;财力不够又必须在公共场合&#xff08;例如图书馆&#xff09;进行使用的时候&#xff0c;就会非常尴尬&#xff08;当然有社交牛逼症的请退出这篇文章&#xff09;&#xff0…

Linux普通用户su root权限的开启和禁止

Linux 普通用户su root 权限的开启和禁止 linux系统为了限制权限&#xff0c;有时候需要禁止普通用户su到root用户, 首先先说明一下&#xff1a; su #只是切换到root用户&#xff0c; 不改变当前目录&#xff1b; su - #切换到root和改变目录到/rootwheel组的介绍 在L…

论文笔记--Improving Language Understanding by Generative Pre-Training

论文笔记GPT1--Improving Language Understanding by Generative Pre-Training 1. 文章简介2. 文章导读2.1 概括2.2 文章重点技术2.2.1 无监督预训练2.2.2 有监督微调2.2.3 不同微调任务的输入 3. Bert&GPT4. 文章亮点5. 原文传送门6. References 1. 文章简介 标题&#x…

增强语言模型导读

以ChatGPT为主的大语言模型出现已有半年时间&#xff0c;研究逐渐从针对模型本身的进化和功能&#xff0c;延展到如何更为有效地利用大模型&#xff0c;将它与其它工具结合&#xff0c;落地&#xff0c;以解决实际领域中的问题。 这里的增强主要指让大语言模型&#xff08;LM&…

GPT 系列论文泛读

目录 1. GPT-1 1.1 无监督预训练 1.2 有监督的微调 2. GPT-2 3. GPT-3 4. InstructGPT 1. Supervised Fine-Tuning (SFT) 2. Reward Modeling (RM) 3. Reinforcement Learning (RL) 这篇写给自己的总结会相对比较简短&#xff0c;因为 GPT 系列的每篇论文都很长&#…

chatGPT-4论文导读:百年未有之大变局-(2)(转载)

声明&#xff1a;本文已征得原作者&#xff1a;荔枝海豹&#xff0c;同意后转载。 原文链接&#xff1a;chatGPT-4论文导读&#xff1a;百年未有之大变局-&#xff08;2&#xff09; - 知乎 在开始讲解之前&#xff0c;我们先说个梗&#xff0c; open AI&#xff0c;从这个名…

吴恩达联手OpenAI上线免费课程:一个半小时学会ChatGPT Prompt工程

点击上方“Python与机器智能”&#xff0c;选择“星标”公众号 第一时间获取价值内容 编辑&#xff1a;张倩 吴恩达亲自授课。 ChatGPT 来了&#xff0c;一切变化都快了起来&#xff0c;一些科技公司开始招募「prompt 工程师」。与写代码的传统计算机工程师不同&#xff0c;Pro…

0基础转行网络安全,选择pwn还是web?

随着5G、工业互联网、人工智能等新兴领域技术的兴起&#xff0c;从而快速推动了各国从人人互联迈向万物互联的时代。 奇安信董事长齐向东曾说过&#xff1a;“如果说5G带来了物联网和人工智能的风口&#xff0c;那么网络安全行业就是风口的平方——风口的风口。" 因此&…

网络安全从业人员2023年后真的会被AI取代吗?

随着ChatGPT的火爆&#xff0c;很多人开始担心网络安全从业人员会被AI取代。如果说网络安全挖洞的话&#xff0c;AI可能真的能取代。但是网络安全不仅仅只是挖洞&#xff0c;所以AI只是能缓解网络安全人员不足的情况&#xff0c;但是是不会取代人类的作用的。 就拿最近很火的C…

Proxy Authentication Required解决

症状 <script type"text/javascript">loadTOCNode(1, symptoms);</script> 如果 Internet Security and Acceleration (ISA) Server 2000 是链接到上游 Web 代理服务器, Web 浏览器中可能会收到完整 HTML 页和随机身份验证提示。 如果下游 ISAServer 计算…

chatgpt赋能Python-python_keyring

Python Keyring: 快速&#xff0c;安全&#xff0c;便捷地管理你的密码 如果你是一个 Python 应用程序开发者&#xff0c;你必须面对有关密码管理的问题。当然&#xff0c;你可以将密码明文硬编码到你的代码中&#xff0c;但是这会很快变得混乱和难以维护。更好的方法是使用 P…

一次疑似 JVM native 内存泄漏的排查实录

最近开发同学反馈&#xff0c;某定时任务服务疑似有内存泄漏&#xff0c;整个进程的内存占用比 Xmx 内存大不少&#xff0c;而且看起来是缓慢上升的&#xff0c;做了下面这次分析&#xff0c;包括下面的内容&#xff1a; 分析 JVM native 内存的一些常见思路内存增长了&#x…

【618期间】超过200小时的课程全都有优惠,全年最好的加入有三AI学习的时间来了~...

正值2023年618期间&#xff0c;既然是全民购物节&#xff0c;有三AI所有付费的视频课程开启优惠活动&#xff0c;即日起至节日结束&#xff08;6月18日晚23:59&#xff09;。 当前已有课程包括数据使用/模型分析/图像分类/图像分割/目标检测/图像生成/图像翻译/图像增强/视频分…

虚假新闻检测概述

几个概念 社交网络的新闻往往包括新闻内容&#xff0c;社交上下文内容&#xff0c;以及外部知识。其中新闻内容指的是文章中所包含的文本信息以及图片视频等多模态信息。社交上下文信息指的是新闻的发布者&#xff0c;新闻的传播网络&#xff0c;以及其他用户对新闻的评论和转发…

认识ChatGPT

ai是由dutuai训练的一种大型自然语言处理模型&#xff0c;能够进行自然语言对话。它基于预训练的语言模型gpt&#xff08;generative pre-trained transformer&#xff09;&#xff0c;具有强大的自然语言理解和生成能力。ai可以通过了解上下文并推断回应来与用户进行交互。它被…

ChatGPT之后何去何从?LeCun新作:全面综述下一代「增强语言模型」

来自&#xff1a;新智元 【导读】语言模型该怎么增强&#xff1f; ChatGPT算是点燃了语言模型的一把火&#xff0c;NLP的从业者都在反思与总结未来的研究方向。 最近图灵奖得主Yann LeCun参与撰写了一篇关于「增强语言模型」的综述&#xff0c;回顾了语言模型与推理技能和使用工…

数据库mysql

目录 数据库的实用性 操作网上商城数据库系统 维护数据库的完整性&#xff08;过&#xff09; 维护数据库的完整性是确保数据库数据的正确性和一致性的关键。以下是一些常见的方法来维护数据库的完整性&#xff1a; 添加修改和删除数据 查询网上商城系统数据 选择列 排…