访问者模式(Visitor)及代码实现

23 篇文章 0 订阅
订阅专栏
访问者模式允许在不修改已有类代码的情况下,通过引入访问者角色来增加新的功能。它将数据结构与数据操作解耦,适用于一系列相似对象需要提供多种功能的情况。然而,当元素类改变时,所有访问者类可能都需要修改,这违背了开闭原则。示例展示了在购买礼物场景中,顾客和店主作为访问者对不同礼物进行不同处理的过程。使用访问者模式需谨慎,因为它可能会增加代码复杂性和理解难度。
摘要由CSDN通过智能技术生成

模式定义:

在不修改现有类的代码的情况下,通过 将类的对象 赋值给其他 类进行操作,从而增加新的功能的方式为 访问者模式;

 

生活中的例子

  • 去服饰店买衣服时,客户对不同类型的衣服 的价格持不同意见; 店员对不同类型的衣服 推销时的话术也不同;
  • 举个贴切的例子吧,正好项目要上线;  项目上到预发布环境,产品 检查项目是否满足需求,测试 检查项目是否有bug,开发 等着项目出bug......

 

何时该使用此模式:

  • 在不想改变现有类的结构代码,又想增加新的功能,可以使用此模式 以增加最少代码为代价增加新功能;
  • 一系列相似对象 需要提供 多种不同且不相关的功能时,且 尽量减少现有类的变化导致的风险时,可以使用此模式;

实现方式:

 

该模式关键的角色:

  • 抽象访问者角色(Abs Visitor): 定义一个公共的访问具体元素的抽象方法,参数为 具体的元素对象
  • 具体访问者角色(Concrete Visitor):实现 访问具体元素的 方法;注意 需要实现 双分派功能(你的对象里的变量有我这个对象,我的对象里的变量有你这个对象);
  • 抽象元素角色(Abs Element): 定义一个 供 访问者 访问的抽象方法; 参数为 访问者对象;
  • 具体元素角色(Concrete Element): 实现 供访问者 访问的方法;注意 需要实现 双分派功能(你中有我,我中有你);

该模式的主要优缺点如下:

优点:

  • 部分符合 开闭原则: 在只增加 访问者 功能时,只需按照规则 增加新的访问者即可,完全满足开闭原则;但是 在 增加元素时,不仅增加了 新的元素类,访问者类中 同样增加;
  • 符合单一职责原则: 此模式将 对数据处理的功能 解耦在每个访问者中,达到 每个访问者功能单一的目的;
  • 将 数据结构 和 数据处理进行解耦; 数据处理在 访问者类中,数据结构在 元素类中;  这样在有新的数据处理功能时 能快速扩展;

缺点:

  • 只要 元素 类有所修改,对应的 所有访问者 类都要修改; 不符合开闭原则;
  • 违反依赖倒置原则; 访问者类 依赖具体的 元素类来进行对应操作;而不是依赖抽象类;
  • 破坏封装;  具体元素对 访问者暴露无遗, 没有提供封装(也正是因为这种特点 才能让访问者完全操作元素);
  • 使代码 更加复杂,理解起来更加困难,特别是 双分派功能的使用

和 其他模式 的 比较:

与 原型模式 比较: 两者没啥相关性,但是 在不想修改元素对象时,可以结合使用; 

 

示例代码部分:

# -*- coding: utf-8 -*-
"""
(C) rgc
All rights reserved
create time '2020/12/29 19:31'

Usage:
访问者模式示例
购买各种礼物时 顾客和店主 对礼物的处理不同;顾客考虑礼物价格是否划算,大小是否合适,店主考虑礼物 根据价格和大小 应该怎么包装才合适
这个需求中 各种礼物是 元素;顾客和店主 是访问者;
假如现在有2种礼物,则顾客和店主需要 共需要实现 2*2=4种访问方法
   现在增加到了5种礼物,则顾客和店主需要 共需要实现 2*5=10种方法方法
因为顾客和店主 对每种礼物 都要分别进行相应操作;
"""
from abc import ABC, abstractmethod


class Gift(ABC):
    """
    礼物基类
    抽象元素角色
    """

    def __init__(self, price, height):
        self.price = price
        self.height = height

    @abstractmethod
    def accept(self, visitor):
        """

        :param visitor:
        :return:
        """
        pass


class Lighter(Gift):
    """
    打火机类
    具体元素角色
    """

    def accept(self, visitor):
        """

        :param visitor:
        :return:
        """
        return visitor.visit_lighter(self)


class Toys(Gift):
    """
    玩具类
    具体元素角色
    """

    def accept(self, visitor):
        """

        :param visitor:
        :return:
        """
        return visitor.visit_toys(self)


class Cup(Gift):
    """
    杯子类
    具体元素角色
    """

    def accept(self, visitor):
        """

        :param visitor:
        :return:
        """
        return visitor.visit_cup(self)


class Person(ABC):
    """
    人 类
    抽象访问者角色
    """

    @abstractmethod
    def visit_lighter(self, element: Lighter):
        """
        对 打火机礼物进行的操作
        :param element:
        :return:
        """
        pass

    @abstractmethod
    def visit_toys(self, element: Toys):
        """
        对 玩具礼物进行的操作
        :param element:
        :return:
        """
        pass

    @abstractmethod
    def visit_cup(self, element: Cup):
        """
        对 杯子 礼物进行的操作
        :param element:
        :return:
        """
        pass


class Customer(Person):
    """
    顾客 类
    具体访问者角色
    """

    def visit_lighter(self, element: Lighter):
        """
        对 打火机礼物进行的操作
        :param element:
        :return:
        """
        if element.height < 7:
            print('打火机大小还行')
        else:
            print('打火机太大了,不方便')
        if element.price > 2000:
            print('什么破打火机怎么这么贵')
        else:
            print('嗯...,这个打火机还行')
            return True
        return False

    def visit_toys(self, element: Toys):
        """
        对 玩具礼物进行的操作
        :param element:
        :return:
        """
        print('玩具不在乎高度问题')
        if element.price > 2000:
            print('天啊,这个玩具好贵啊')
            return False
        print('小意思,这个玩具可以考虑')
        return True

    def visit_cup(self, element: Cup):
        """
        对 杯子 礼物进行的操作
        :param element:
        :return:
        """
        print('杯子不考虑高度问题')
        if 100 < element.price < 300:
            print('这个杯子可以,不贵也不便宜')
            return True
        print('不考虑这个杯子')
        return False


class Clerk(Person):
    """
    店员 类
    具体访问者角色
    """

    def visit_lighter(self, element: Lighter):
        """
        对 打火机礼物进行的操作
        :param element:
        :return:
        """
        if element.height > 6:
            print('这个打火机要用长点的盒子包装')
        else:
            print('这个打火机用小盒子包装就行了')

    def visit_toys(self, element: Toys):
        """
        对 玩具礼物进行的操作
        :param element:
        :return:
        """
        if element.price > 1000:
            print('这个玩具挺贵的,用高档材料包装吧')
        else:
            print('这个玩具价格一般,随便包装一下吧')

    def visit_cup(self, element: Cup):
        """
        对 杯子 礼物进行的操作
        :param element:
        :return:
        """
        if element.height > 10:
            print('这个杯子有点大,用箱子包装吧')
        else:
            print('挺小一杯子,用小盒子吧,别浪费资源')


if __name__ == '__main__':
    # 各种礼物初始化
    gifts = [Lighter(3000, 6), Toys(2000, 50), Cup(200, 10)]

    print('客户挑选礼物')
    customer_visitor = Customer()
    # 礼物列表
    choose_gift_list = []
    # 查看每个礼物
    for gift in gifts:
        # 把心仪的礼物放到礼物列表中
        if gift.accept(customer_visitor):
            choose_gift_list.append(gift)

    print('*' * 10)

    print(f'店员看到到顾客选择了{len(choose_gift_list)}个礼物,现在开始包装')
    clerk_visitor = Clerk()
    # 店员对顾客选择的礼物进行包装
    for gift in choose_gift_list:
        gift.accept(clerk_visitor)

运行结果:

 

总结: 

注意 在访问者类 中操作 元素对象时,除非需要,否则尽量不要修改现有对象属性值(可以通过 原型模式进行克隆),防止 影响后续操作;

这种模式 打破了 程序员编写代码时的思想禁锢, 一般都是 数据对象增加新功能时 都是在类中直接增加新的方法; 而此模式 将 新功能放在单独的类中;

 

相关链接:

https://refactoringguru.cn/design-patterns/visitor

https://refactoringguru.cn/design-patterns/visitor/python/example

http://c.biancheng.net/view/1397.html

https://www.cnblogs.com/liuqingzheng/articles/10039702.html

 

设计模式C++学习之访问者模式Visitor
09-07
在`Demo18_Visitor`中,我们可以看到一个具体的访问者模式实现示例,通过阅读源代码,可以更好地理解访问者模式的运作机制。代码通常会展示如何定义和使用访问者接口,以及如何在元素类中调用`accept`方法以执行特定...
设计模式-行为型模式:访问者模式
逐梦苍穹的博客
02-23 818
访问者模式是一种行为型设计模式,它可以在不改变对象结构的前提下,定义新的操作或行为。该模式将数据结构和数据操作分离,使得数据结构和数据操作可以独立地变化。
简简单单实现访问者模式
alian
04-02 108
基本实现:访问者包含访问方法,参数为被访问的对象,目标对象应该包含接收方法,接收访问对象。访问者模式实现数据和操作分离,通过访问者对目标对象进行修改。
设计模式——访问者模式Visitor Pattern)+ Spring相关源码
最新发布
码鹿的记录
10-26 1107
访问者模式,将 数据结构 与 数据操作 分离。
Java设计模式(八)—— 访问者模式
weixin_49561506的博客
03-28 757
设计模式访问者模式
设计模式VISITOR模式
行到水穷处 坐看云起时
09-28 1598
最近在项目中用到了VISITOR模式,总结一下,自己也再学习一遍,同时和大家分享。 我最初遇到设计模式的时候,有这些疑问:什么设计模式在什么情况下可以解决什么问题?设计模式的最大特点是抽象,并不难,所以 选择合适的例子,对于理解某种设计模式至关重要。先讲几句题外话,设计模式的目的是解决软件工程中代码重用、系统可扩展以及使 代码结构更加清晰等问题,采用某种设计模式之后,可能会产
访问者模式简介和java代码实现
07-05
为了解决这一问题,访问者模式可以采用双分派实现,即在元素类中也包含一个访问者类型参数,这样在访问者接口中只需要声明一个通用的 visit 方法,而元素类则根据自身类型决定调用哪个具体方法。 双分派的实现原理...
php设计模式 Visitor 访问者模式
10-28
访问者模式Visitor Pattern)是一种行为设计模式,它在不修改已有对象结构的情况下,为对象增加新的功能。这种模式在PHP和其他面向对象编程语言中都得到了广泛应用,尤其在需要对对象进行多样化操作,且不想破坏...
设计模式-访问者模式Visitor
09-20
访问者模式Visitor)是一种行为设计模式,它允许在不修改对象结构的前提下向对象结构中的元素添加新的操作。这种模式的核心思想是分离了算法和对象结构,使得算法可以在不改变对象结构的情况下独立变化。 访问者...
实例讲解iOS应用的设计模式开发中的Visitor访问者模式
09-02
访问者模式Visitor Pattern)是一种行为设计模式,它在对象结构中定义了一个访问者的接口,使得该访问者能访问该结构中的元素,并执行特定的操作,而不会破坏对象结构。这种模式将数据结构与操作分离,增加了系统...
访问者模式代码
03-14
访问者模式代码
Visitor(访问者) java实现
12-05 421
package Visitor.MyTest; import java.util.Collection; import java.util.Iterator; /** * 采访者 * @author Administrator */ public abstract class Visitor { public void visit(Visitable visitable) { /
设计模式——访问者模式(附代码示例)
枫陵的博客
05-25 974
一. 传统模式 以观众(分为男女两类)对歌手评价(分为成功、失败两类)为例 1. 传统方式解决 通过继承的方式实现男女分类,并直接在类中实现评价方法 2. 传统方式问题分析 如果系统比较小,还是可以的,但是考虑系统增加越来越多新的功能时,对代码改动较大,违反了ocp原则,不利于维护; 且扩展性不好,比如增加了新的人员类型,或者管理方法。故引出访问者模式。 二. 访问者模式 1. 概念 访问者模式(Visitor Pattern),封装一些作用于某种数据...
设计模式访问者模式代码示例
yurenjiemimi的专栏
07-22 633
问题:根据电表显示的用电量计算用户的电费,注意:电表用不同的电表,电费有不同的计算方法 解析:运用访问者模式。访问这模式结构:1、抽象访问者(一般用接口来实现);2、具体访问者(实现接口的类);3、抽象元素(一般用抽象类实现);4、具体元素(继承抽象类的类)。在本问题中,电表用抽象类抽象出来,计费方法看成是计表员接口,而用不同的计费方法来实现这个计表员访问者接口。 package fa
访问者模式代码举例(java语言版)
qq_35386002的博客
04-16 393
前言:服访问者模式解决稳定的数据结构和易变的操作耦合问题。比如下面例子:鼠标,显示器,键盘,电脑它们的关系就是稳定的,所以鼠标,显示器,键盘,电脑实体类组成的结构就是稳定的数据结构。访问方式是多变的,所以可以在访问的时候根据具体需求去访问。 JAVA语言版访问者模式 创建电脑接口: public interface ComputerPart { void accept(Comput...
组合模式详解附有代码案例分析(包含透明组合模式、安全组合模式的代码示例)
hyyyya的博客
10-14 1361
组合模式一、组合模式的概念和角色(一)、组合模式的概念(二)、组合模式的角色二、组合模式的应用场景三、透明组合模式的代码示例四、安全组合模式的代码示例五、组合模式的优缺点(一)、优点(二)、缺点 一、组合模式的概念和角色 (一)、组合模式的概念 ​ 组合模式也称为整体-部分模式,它的宗旨是通过将单个对象(叶子节点)和组合对象(树枝节点)用相同的接口进行表示,使得客户对单个对象和组合对象的使用具有一致性,属于结构型模式。 ​ 组合模式一般用来描述整体和部分的关系,它将对象组织到树形结构中,最顶层的节点成为
浅析设计模式访问者模式(Visitor)
SomeoneMH的博客
06-07 4880
观察者模式(Visitor)
设计模式——访问者模式(代码基本参考自《大话设计模式》)
weixin_41960204的博客
10-31 124
public abstract class Element { public abstract void accept(Visitor visitor); } public abstract class Visitor { public abstract void visitConcreteElementA(ConcreteElementA concreteElementA); public abstract void visitConcreteElementB(ConcreteElementB
设计模式——访问者模式
dianhuopao7502的博客
05-04 108
  访问者模式是对象的行为模式。访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变。 主要角色   抽象访问者:抽象类或者接口,声明访问者可以访问哪些元素,具体到程序中就是visit方法中的参数定义哪些对象是可以被访问的。  访问者:实现抽象访问者所声明的方法,它影响到访问者访问到一个类后该干什么,要做什么事情。...
访问者模式(VisitorPattern)——封装操作与数据结构
"访问者模式(VisitorPattern)是一种软件设计模式,旨在封装对特定数据结构元素的操作,并允许这些操作在不改变数据结构的情况下独立变化。当需要对包含多种类型的元素集合进行操作,且操作因元素类型不同而有所差异...
写文章

热门文章

  • joblib的Parallel并发计算使用总结及优化 10370
  • scrapy回调函数传递参数 9210
  • Python多线程实现 as_completed先返回的任务先处理 在 阿里云 函数式计算 优化的应用 8237
  • PySpark reduce reduceByKey用法 5407
  • PySpark map mapValues用法 4984

分类专栏

  • rabbitmq 5篇
  • go 8篇
  • 物联网视频监控 5篇
  • etcd 1篇
  • mongo 2篇
  • gin 1篇
  • 高性能 9篇
  • celery 3篇
  • 设计模式 23篇
  • 进程 1篇
  • PySpark 9篇
  • linux 2篇
  • 进程间同步 1篇
  • 布隆过滤器 1篇
  • pytest 1篇
  • pyautogui 1篇
  • 线程 1篇
  • 数据库 5篇
  • python 38篇
  • scrapy 1篇
  • pycharm 1篇

最新评论

  • celery执行池概览

    北风之神c: 总结的很全面,写得赞,博主用心了。 celery对目录层级文件名称格式要求太高,只适合规划新的项目,对不规则文件夹套用难度高。 所以新手使用celery很仔细的建立文件夹名字、文件夹层级、python文件名字。 所以网上的celery博客教程虽然很多,但是并不能学会使用,因为要运行起来需要以下6个方面都掌握好,博客文字很难表达清楚或者没有写全面以下6个方面。 celery消费任务不执行或者报错NotRegistered,与很多方面有关系,如果要别人排错,至少要发以下6方面的截图,因为与一下6点关系很大。 1)整个项目目录结构, 2)@task入参 ,3)celery的配置,4)celery的配置 include ,5)cmd命令行启动参数 --queues= 的值,6)用户在启动cmd命令行时候,用户所在的文件夹。 在不规范的文件夹路径下,使用celery难度很高,一般教程都没教。 [项目文件夹目录格式不规范下的celery使用演示](https://github.com/ydf0509/celery_demo) 。 此国产分布式函数调度框架 funboost python万能通用函数加速器 https://funboost.readthedocs.io/zh-cn/latest/articles/c1.html , 从用法调用难度,用户所需代码量,超高并发性能,qps控频精确程度,支持的中间件类型,任务控制方式,稳定程度等20个方面全方位超过celery。发布性能提高1000%,消费性能提高2000%。 python万能分布式函数调度框架funboost支持python所有类型的并发模式和一切知名消息队列中间件,python函数加速器,只需要一行代码调度任意函数,框架包罗万象,万能编程功能宝典,一统编程思维,与业务不绑定,适用范围广。 pip install funboost

  • 物联网视频监控服务(三)-监控服务端 篇

    qq_58685443: 没有嘞,最好还是用rstp推流或者是http吧

  • 物联网视频监控服务(三)-监控服务端 篇

    m0_52854542: 我也是用mqtt协议发送图片,帧率低,你之后有好的改进方案吗

  • joblib的Parallel并发计算使用总结及优化

    Rrriobun: 为什么会出现问题2这种问题啊?(问题2: 在使用loky进行多进程并发时,无法 实现 先执行完的任务先返回给 用户端 的功能,让我的接口效应时间大打折扣;)

  • 物联网视频监控服务(三)-监控服务端 篇

    qq_58685443: 博主用这个方案帧率怎么样啊,我没加其他功能,直接解析通过mqtt协议发来图片帧率好低表情包

大家在看

  • Sunbit币昇交易所分析戴维医疗创始人陈云勤因病去世,享年82岁
  • 【C语言基础题分享】打印数字金字塔(PTA) 157
  • 电脑分流抢票软件 Bypass 下载及使用说明
  • 力扣 中等 1901.寻找峰值II
  • 01 [51单片机 PROTEUS仿真设计]基于温度传感器的恒温控制系统 1439

最新文章

  • Ray使用备注
  • 物联网视频监控服务(一)-硬件选择篇
  • 物联网视频监控服务(二)-硬件编码篇
2023年9篇
2022年9篇
2021年37篇
2020年39篇
2019年29篇
2018年58篇
2017年4篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

玻璃钢生产厂家奉贤玻璃钢雕塑工程西安 玻璃钢雕塑定制黑河园林玻璃钢雕塑厂家四川人物玻璃钢雕塑定制景观玻璃钢雕塑专业公司贵州玻璃钢雕塑小品乌鲁木齐气球商场美陈费用情况河南节庆商场美陈市场价自贡成都商场美陈资讯潮州古代玻璃钢人物雕塑梅州市玻璃钢雕塑制作大型玻璃钢卡通雕塑石材玻璃钢雕塑定制莱西玻璃钢卡通雕塑偃师玻璃钢雕塑厂家嘉兴欧式玻璃钢雕塑价位济南商场美陈供应商佛山玻璃钢仿铜雕塑四川公园玻璃钢雕塑设计青海城市标志玻璃钢雕塑宝鸡水景校园玻璃钢雕塑厂家蒙城商场中秋美陈青海玻璃钢卡通雕塑福州玻璃钢仿真动物雕塑校园玻璃钢花盆造型铜仁商场美陈布置烟台襄阳玻璃钢面包雕塑玻璃钢动物雕塑咨询靠谱的玻璃钢雕塑设计雕塑用的玻璃钢是什材料香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化