设计模式25-访问器模式

news2024/9/25 19:18:46

设计模式25-访问器模式

  • 访问者模式的动机
  • 定义与结构
    • 定义
    • 结构
      • 访问者模式概述
      • 结构图解析
      • 总结
  • C++代码推导
    • 原理代码
    • 实例代码
  • 优缺点
  • 应用
  • 总结

访问者模式的动机

  • 在软件构建过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为方法。此时如果直接在基类中做这样的更改,将会给此类带来繁重的变更负担,甚至破坏原有设计。
  • 那么如何在不更改类层次结构的前提下,定义时根据需要的透明的为内层次结构上的各个类动态添加新的操作。从而避免上述问题。
  • 当需要对一个对象结构中的各个元素进行不同的操作,而这些操作可能会频繁改变时,通常我们会将这些操作直接放在对象类的内部。然而,这样的设计违反了单一职责原则,因为对象类不仅需要管理自身的数据,还要处理不同的操作逻辑。更糟糕的是,如果需要添加新的操作,则必须修改对象类,这会导致类结构的频繁变化和难以维护。
  • 访问者模式通过将数据结构与操作解耦,使得我们可以在不修改数据结构的情况下增加新的操作。访问者模式允许你将操作封装在访问者对象中,将对结构元素的操作与数据结构本身分开,这样可以增加新的操作而不改变数据结构。

定义与结构

定义

访问者模式(Visitor Pattern)是一种行为设计模式,它将对数据结构中的元素进行操作的功能封装到访问者对象中,使得在不改变数据结构的前提下增加新的操作变得容易。

结构

在这里插入图片描述

根据您提供的图片理解信息和图片中的文字文本,这是一张关于访问者模式(Visitor Pattern)的结构图。我将详细解释这张图的内容。

访问者模式概述

访问者模式是一种将算法与对象结构分离的设计模式,它定义了一组操作,可以在不修改对象结构的前提下为对象结构中每个元素添加新的操作。这种模式通常用于对象结构中的元素需要被不同方式处理的情况。

结构图解析

  1. Client(客户端)

    • 客户端是访问者模式的使用者,它负责创建并配置对象结构以及访问者对象,然后让访问者对象访问并处理结构中的元素。
  2. Visitor(访问者)

    • 这是一个抽象访问者类,它定义了一个或多个访问操作,这些操作将用于访问对象结构中的元素。具体访问者(如ConcreteVisitor1ConcreteVisitor2)将实现这些方法,以定义对元素的具体访问操作。
  3. ConcreteVisitor1 和 ConcreteVisitor2

    • 这两个是具体访问者类,它们实现了Visitor接口中定义的访问操作。每个具体访问者都包含了访问特定元素(如ConcreteElementAConcreteElementB)的方法实现,这些方法的具体行为可以不同。
  4. Element(元素)

    • 这是一个抽象元素类,它声明了一个接受访问者对象的accept方法。这个方法的目的是让访问者能够访问到元素本身,并对元素执行操作。
  5. ConcreteElementA 和 ConcreteElementB

    • 这两个是具体元素类,它们实现了Element接口。每个具体元素类都包含了与自身相关的数据和操作,以及accept方法的实现,该方法允许访问者访问元素的数据并对其进行处理。
  6. accept(Visitor v)

    • 这是Element接口和所有具体元素类中都有的方法。它接受一个访问者对象作为参数,并调用访问者的访问方法,从而允许访问者对元素进行操作。注意,图片中的文字可能有些混淆,因为accept方法的参数是Visitor类型,但示例中的Accept(Visitor v)可能是想要表达这个含义。
  7. VisitConcreteElementA(ConcreteElementA) 和 VisitConcreteElementB(ConcreteElementB)

    • 这些方法名可能是为了说明客户端如何调用访问者来访问特定元素,但在标准的访问者模式中,客户端通常不会直接调用这样的方法。相反,客户端会调用元素的accept方法,并将访问者对象作为参数传递,由accept方法内部调用访问者的相应方法。
  8. OperationA() 和 OperationB()

    • 这些可能是ConcreteVisitor1ConcreteVisitor2类中定义的具体操作方法,用于对元素执行具体的访问操作。图片中的文本并未直接展示这些方法属于哪个类,但我们可以推断它们属于具体访问者类。

总结

这张图展示了访问者模式的主要组成部分:抽象访问者、具体访问者、抽象元素和具体元素。客户端通过创建并配置对象结构以及访问者对象,然后让访问者访问并处理结构中的元素,从而实现算法与对象结构的分离。需要注意的是,图片中的某些文本(如“Client”和“VisitConcreteElementA(ConcreteElementA)”的重复)可能存在拼写或表示上的混淆。

C++代码推导

原理代码

#include <iostream>
using namespace std;

class Visitor;


class Element
{
public:
    virtual void accept(Visitor& visitor) = 0; //第一次多态辨析

    virtual ~Element(){}
};

class ElementA : public Element
{
public:
    void accept(Visitor &visitor) override {
        visitor.visitElementA(*this);
    }
    

};

class ElementB : public Element
{
public:
    void accept(Visitor &visitor) override {
        visitor.visitElementB(*this); //第二次多态辨析
    }

};


class Visitor{
public:
    virtual void visitElementA(ElementA& element) = 0;
    virtual void visitElementB(ElementB& element) = 0;
    
    virtual ~Visitor(){}
};

//==================================

//扩展1
class Visitor1 : public Visitor{
public:
    void visitElementA(ElementA& element) override{
        cout << "Visitor1 is processing ElementA" << endl;
    }
        
    void visitElementB(ElementB& element) override{
        cout << "Visitor1 is processing ElementB" << endl;
    }
};
     
//扩展2
class Visitor2 : public Visitor{
public:
    void visitElementA(ElementA& element) override{
        cout << "Visitor2 is processing ElementA" << endl;
    }
    
    void visitElementB(ElementB& element) override{
        cout << "Visitor2 is processing ElementB" << endl;
    }
};
        
    

        
int main()
{
    Visitor2 visitor;
    ElementB elementB;
    elementB.accept(visitor);// double dispatch
    
    ElementA elementA;
    elementA.accept(visitor);

    
    return 0;
}

实例代码

以下是一个使用访问者模式的C++代码示例。假设我们有一组不同类型的图形元素(例如CircleRectangle),并希望对这些元素进行不同的操作(例如计算面积和绘制)。

#include <iostream>
#include <vector>
#include <memory>

// 声明访问者接口
class Circle;
class Rectangle;

class Visitor {
public:
    virtual void visit(Circle& circle) = 0;
    virtual void visit(Rectangle& rectangle) = 0;
};

// 声明元素接口
class Element {
public:
    virtual ~Element() = default;
    virtual void accept(Visitor& visitor) = 0;
};

// 具体元素类:圆形
class Circle : public Element {
public:
    void accept(Visitor& visitor) override {
        visitor.visit(*this);
    }

    double getRadius() const {
        return radius_;
    }

private:
    double radius_ = 5.0;
};

// 具体元素类:矩形
class Rectangle : public Element {
public:
    void accept(Visitor& visitor) override {
        visitor.visit(*this);
    }

    double getWidth() const {
        return width_;
    }

    double getHeight() const {
        return height_;
    }

private:
    double width_ = 4.0;
    double height_ = 6.0;
};

// 具体访问者类:计算面积
class AreaVisitor : public Visitor {
public:
    void visit(Circle& circle) override {
        double area = 3.14159 * circle.getRadius() * circle.getRadius();
        std::cout << "Circle Area: " << area << std::endl;
    }

    void visit(Rectangle& rectangle) override {
        double area = rectangle.getWidth() * rectangle.getHeight();
        std::cout << "Rectangle Area: " << area << std::endl;
    }
};

// 具体访问者类:绘制图形
class DrawVisitor : public Visitor {
public:
    void visit(Circle& circle) override {
        std::cout << "Drawing Circle with radius " << circle.getRadius() << std::endl;
    }

    void visit(Rectangle& rectangle) override {
        std::cout << "Drawing Rectangle with width " << rectangle.getWidth() << " and height " << rectangle.getHeight() << std::endl;
    }
};

int main() {
    std::vector<std::shared_ptr<Element>> elements;
    elements.push_back(std::make_shared<Circle>());
    elements.push_back(std::make_shared<Rectangle>());

    AreaVisitor areaVisitor;
    DrawVisitor drawVisitor;

    // 遍历所有元素并进行计算面积操作
    for (auto& element : elements) {
        element->accept(areaVisitor);
    }

    // 遍历所有元素并进行绘制操作
    for (auto& element : elements) {
        element->accept(drawVisitor);
    }

    return 0;
}

优缺点

优点

  1. 遵循单一职责原则:将具体操作从数据结构中分离,避免数据结构的修改。
  2. 增加新操作容易:可以通过增加新的访问者类来添加新的操作,而无需修改现有的数据结构。
  3. 简化复杂操作:使得复杂操作的代码组织更加清晰,访问者模式将相关操作集中到一个访问者中。

缺点

  1. 违反开闭原则:虽然可以增加新的操作,但如果要添加新的数据结构类型,需要修改所有访问者的代码。
  2. 对象结构的公开:访问者模式要求所有元素都必须公开自己,使得访问者可以访问其内部数据,这可能破坏封装性。
  3. 依赖具体的元素接口:访问者模式要求元素必须有接受访问者的接口,因此在动态类型系统中应用不太方便。

应用

  1. 编译器:编译器使用访问者模式来遍历语法树并执行语法分析、优化、代码生成等操作。
  2. 对象结构稳定且操作频繁变化的系统:在对象结构较为稳定,但操作经常变化的系统中,例如图形绘制系统、报表生成系统。
  3. 跨不同类的操作:需要跨越多个类对其进行不同的操作时,如文件系统的遍历和操作(查找、统计、复制等)。

访问者模式在需要处理复杂结构并且操作可能频繁变化的场景中非常有用。通过将操作封装在访问者对象中,它提供了对系统进行扩展的灵活性,同时保持了代码的清晰性和可维护性。

总结

  • 访问器模式通过所谓双重分发来实现在不更改(不添加新的操作)Element(元素)类层次结构的前提下,在运行时透明的微类层次结构上的各个类动态添加新的操作。
  • 所谓双重分发就是访问器模式中间包括了两个多态分发,第一个为accept方法的多态辨析。第二个为VisitConcreteElementX方法的多态辨析.
  • 访问器模式的最大缺点在于扩展类层次(既添即添加新的元素子类会导致访问器类的改变,因此访问性模式适用于元素类层次结构稳定的状态。而其中的操作却经常面临频繁改动。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

169页PPT丨城投公司战略规划之产业投资商规划

一、规划背景与目标随着经济的不断发展和市场环境的变化&#xff0c;麦肯新城投公司致力于从传统的城市建设主体向产业投资商转型&#xff0c;以实现可持续发展和提升区域经济活力。 目标&#xff1a;在未来5年内&#xff0c;成为具有核心竞争力和广泛影响力的产业投资商&…

Hadoop: Mapreduce了解

目录 1.MapReduce概述 2.MapReduce的基本工作原理 2.1.Map阶段 2.1.1.Map源码解析 2.1.2.map端代码总结 2.2.Shuffle and Sort阶段 2.3.Reduce阶段 2.3.1.Reduce源码解析 2.3.2.Reduce端源码总结 3.数据流与任务执行 3.1.数据输入与输出格式 3.1.1.TextInputFormat…

【公共科目】简单概率问题

问&#xff1a;在人寿保险事业中&#xff0c;很重视某一年龄段的投保人的死亡率&#xff0c;计入每个投保人能活到65的概率为0.6&#xff0c;问3个投保人中有2个人活到65岁的概率是多少? A 0.126 B 0.388 C 0.432【正确答案】 D 0.534 首先看到这道题&#xff0c;很感慨能活到…

redis分布式是如何实现的(面试版)

需要结合项目中的业务进行回答&#xff0c;通常情况下&#xff0c;分布式锁使用的场景&#xff1a; 集群情况下的定时任务、抢单、幂等性场景。 下面先来看一个抢卷场景&#xff1a; 以下情况会出现超卖情况&#xff1a; 因为线程会交替执行&#xff0c;所以线程查询优惠价的…

学习C语言(18)

整理今天的学习内容 1.strcmp的使用和模拟实现 strcmp是用来比较字符串的大小的 比较方式&#xff1a;比较两个字符串中对应位置上字符ASCII码值的⼤小 第⼀个字符串大于第二个字符串&#xff0c;则返回⼤于0的数字 第⼀个字符串等于第二个字符串&#xff0c;则返回0 第⼀…

Mac M1 Max配置torch-geometric等深度学习库

前提&#xff1a;此电脑中已经安装好了Anaconda环境 &#xff08;一&#xff09;查看创建的虚拟环境中torch的版本 import torch torch.__version__&#xff08;二&#xff09;针对安装的 torch 版本&#xff0c;去官网下载torch-geometric 依赖的对应版本 torch-sparse、tor…

OpenMax算法详解:深度学习中的高效开集识别技术

OpenMax算法详解&#xff1a;深度学习中的高效开集识别技术 在深度学习领域&#xff0c;模型的识别能力往往受限于其训练数据集的范畴。传统的分类模型&#xff0c;如卷积神经网络&#xff08;CNN&#xff09;或循环神经网络&#xff08;RNN&#xff09;&#xff0c;通常被设计…

《大道平渊》· 拾捌 —— 证明自己,本身就毫无意义。

《大道平渊》 我在任何时候都会保持最轻松的状态&#xff0c;选择最舒适的态度和动作。 我在与人交谈时&#xff0c;无论何时何地&#xff0c;都会像在家里躺着和挚友交谈一样轻松。 我总是悠然自若&#xff0c;因为我深知自己的过度表现&#xff0c;只会给人留下怪异的印象。…

django学习入门系列之第十点《django的快速上手》

文章目录 快速上手app注册【settings.py】编写URL和视图的对应关系【urls.py】编写视图函数【views.py】启动django启动网页静态文件路径修改 往期回顾 快速上手 app注册【settings.py】 注意&#xff0c;创建了不代表注册了 操作&#xff0c;在settings里面添加这个 # 一…

002、架构_详解(重点)

GoldenDB 分布式数据库框架 DN和RDB增加了备节点;引入新模块CM,且GTM、MDS、PM、CM都增加备节点;MDS、PM、CM、RDB被统一在了管理节点之中;GTM和MDS间多了一条连线,因为GTM的切换由MDS把控;初步系统架构mysqld:一般称为DB节点,负责单个节点的数据处理; dbproxy:一般…

新手该如何选择与小程序定位相关的关键词

关键词的优化是提高小程序排名的关键步骤之一&#xff0c;所以如何选择与小程序定位相关的关键词是一个很重要的过程&#xff0c;需要考虑多个因素以确保关键词既符合小程序的业务特性&#xff0c;又能吸引目标用户。以下是一些具体的步骤和建议&#xff1a; 1. 深入了解小程序…

<WPF> logic tree 和 visual tree 到依赖属性和路由事件--烂尾睡觉

logic tree 逻辑树通常与 XAML 文件中的元素直接对应。The logical tree comprises the elements as they are listed in the XAML. 用途&#xff1a; 数据绑定&#xff1a;逻辑树用于数据绑定机制&#xff0c;帮助控件获取其父级的属性或数据上下文。事件处理&…

Telnet详解与应用——从原理到实战模拟

1. 引言 在现代网络管理中&#xff0c;远程访问和控制设备的能力至关重要。Telnet是一种经典的远程访问协议&#xff0c;尽管在安全性方面逐渐被SSH等更现代化的协议取代&#xff0c;但其在早期网络管理中的广泛使用使其成为网络工程师的基本技能之一。本文将深入探讨Telnet的…

Shader 透明相关

&#xff11;、设置深度写入与渲染队列 深度写入 深度写入默认是开启&#xff0c;需要通过渲染状态中的 ZWrite off 指令主动关闭深度写入 当我们把它写在Pass渲染通道中时&#xff0c;它只会影响该Pass 若我们把它写在SubShader语句块中&#xff0c;它将影响其中的所有Pass …

Dubbo负载均衡的5种策略及适用场景

Dubbo负载均衡的5种策略及适用场景 1. Random LoadBalance&#xff08;默认&#xff09;2. RoundRobin LoadBalance3. LeastActive LoadBalance4. ConsistentHash LoadBalance &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; Dubbo为优化服务…

Web攻防之应急响应(一)

目录 1. 前言 2. 靶场准备 3. 应急场景 4. 应急实战 4.1 查看服务器开放端口 4.2 通过远程链接工具连接服务器 4.3 寻找中间件日志 4.4. 查看并下载日志 4.5 初步分析日志 4.6 查看安全分析报告 4.6 从被篡改的页面开始 4.6 通过修改的文件时间进一步分析日志信息 4.…

零基础学PLC的指令-位逻辑指令(1)

1、常开触点&#xff1a; 它是一个逻辑开关&#xff0c;可以理解为是电气控制图中的常开按钮&#xff0c;这个逻辑开关是否接通是受寻址的结果而决定的&#xff0c;若I0.0&#xff08;按位寻址&#xff09;的寻址结果为“1”&#xff0c;这个逻辑开关就会导通&#xff0c;若寻…

2.2.2 Posix API与网络协议栈 3

3 断开连接 四次挥手 不分客户端&#xff0c;服务器&#xff0c;只分主动方和被动方 主&#xff1a;tcp包里fin这一位 置1被&#xff1a;回&#xff0c;ack这一位 置1被&#xff1a; fin1主&#xff1a;ack1 与posix api关系&#xff0c;调用了close() &#xff0c;不是网络…

数据库mysql集群主从、高可用MGR、MHA技术详解

一、安装数据库mysql步骤 环境&#xff1a;红帽7.9系统 安装依赖 yum install cmake gcc-c openssl-devel ncurses-devel.x86_64 libtirpc-devel-1.3.3-8.el9_4.x86_64.rpm rpcgen.x86_64 -y 将下载的MySQL软件包解压并cd到mysql的目录下 [rootmysql-node10 ~]# tar zxf mysq…

新手小白Ubuntu18.04超详细安装教程

1、Ubuntu18.04系统下载地址 Ubuntu18.04下载地址 直接下载桌面版 2、Ubuntu18.04安装 &#xff08;1&#xff09;打开VMware虚拟机 文件—>新建虚拟机—>选择典型 &#xff08;2&#xff09;选择稍后安装系统 &#xff08;3&#xff09;选择linux系统&#xff0c;…