当前位置: 首页 > news >正文

实战设计模式之访问者模式

概述

        访问者模式允许我们在不改变类的前提下,向已有类添加新的功能。简单来说,就是将算法与对象的数据结构进行分离的一种方法。在实际应用中,当我们需要对一组对象执行一些操作,而这些操作又需要随着需求的变化而不断变化时,访问者模式就显得尤为重要了。

        电子商务平台的库存管理系统是现实生活中运用访问者模式的一个典型例子。电子商务平台会销售不同种类的商品,比如:书籍、电子产品和服装等。我们需要定期对库存进行不同的统计分析,包括:计算总价值、统计数量等。随着业务的发展,可能会有新的商品类型加入,也可能会有新的统计需求出现。访问者模式允许我们将特定的商品处理逻辑与商品类本身分离,使得添加新的商品类型或处理逻辑变得更为简单和灵活。

基本原理

        访问者模式的核心思想是:将算法与对象结构分离。具体来说,访问者模式通过定义一个操作(通常称为“访问”),这个操作可以在不修改该元素的类的前提下,为每一个具体元素类声明一个该操作。在访问者模式中,我们有两个主要的角色:一个是接受访问的对象集合(即元素),另一个是对这些对象执行操作的访问者。元素知道如何接受访问者,并且会调用访问者的相应方法来完成操作。

        访问者模式主要由以下五个核心组件构成。

        1、访问者。为每一个具体元素声明一个访问操作,表示访问者访问一个元素所要完成的工作。通常情况下,访问者会包含多个Visit方法,每个方法对应一种具体的元素类型。

        2、具体访问者。实现了访问者接口中的每种Visit方法,以完成具体的业务逻辑。

        3、元素。定义了一个接受访问者的接口Accept,其主要作用是让访问者访问自身。同时,Element也是一个抽象类,代表了一组可以被访问的对象。

        4、具体元素。通常是那些需要被访问的对象,实现了Element接口,并提供自身的具体实现。

        5、对象结构。管理元素对象的集合,提供了遍历元素的方法。

        基于上面的核心组件,访问者模式的实现主要有以下五个步骤。

        1、定义元素接口。创建一个抽象类或接口,至少声明了一个Accept方法。该方法用于接收一个访问者对象,并调用访问者的相应Visit方法来执行对当前元素的操作。

        2、创建具体元素类。对于每一个需要被访问的具体元素,创建一个继承自元素接口的类。在每个具体元素类中,实现Accept方法,使其调用传入的访问者对象的对应Visit方法,并传递自身作为参数。

        3、定义访问者接口。创建一个接口,为每种具体访问者类型定义一个Visit方法。这意味着,每当添加一个新的具体访问者类型时,都需要向访问者接口中添加一个新的Visit方法声明。

        4、实现具体访问者类。根据具体的业务逻辑需求,创建实现访问者接口的具体访问者类。在这些类中,实现所有声明的Visit方法,每个方法都包含了针对特定访问者类型的处理逻辑。

        5、创建对象结构。创建一个管理元素集合的对象结构,可以是一个简单的容器,也可以是更复杂的数据结构。此对象结构应提供遍历其内部元素的方法,并能够接受一个访问者对象,依次对其内部的每个元素调用Accept方法。

实战代码

        在下面的实战代码中,我们使用访问者模式模拟了电子商务平台库存管理系统的实现。

        首先,我们定义了一个抽象基类CProduct,它包含商品的基本信息(名称、价格、库存量),并声明了一个纯虚函数Accept用于接收访问者对象。

        接着,我们定义了两个具体的商品类CBook和CElectronics。它们继承自CProduct,并实现了Accept方法。该方法调用传入的访问者的相应Visit方法,以执行针对具体商品类型的特定操作。

        然后,我们定义了一个抽象访问者类CVisitor。其中声明了针对每种商品类型的Visit方法,并通过具体访问者类CStockValueCalculator实现了这些方法,用来计算库存总价值。此外,还有一个管理商品集合的对象结构类CInventory。它负责存储商品实例,并提供了一个PerformCalculations方法遍历所有商品,对每个商品调用其Accept方法,传入具体的访问者对象以执行相应的业务逻辑。

        最后,在main函数中,我们创建了一个CInventory实例。在添加了几种不同类型的商品后,我们使用CStockValueCalculator访问者来计算库存总价值,并最终输出了结果。

#include <iostream>
#include <vector>
#include <string>using namespace std;class CVisitor;// 元素接口
class CProduct
{
public:CProduct(const string& name, double price, int stock) : m_strName(name), m_dbPrice(price), m_nStock(stock) {}virtual ~CProduct() {}virtual void Accept(CVisitor& visitor) = 0;string GetName() const { return m_strName; }double GetPrice() const { return m_dbPrice; }int GetStock() const { return m_nStock; }protected:string m_strName;double m_dbPrice;int m_nStock;
};// 具体元素:书籍
class CBook : public CProduct
{
public:CBook(const string& name, double price, int stock) : CProduct(name, price, stock) {}void Accept(CVisitor& visitor) override;
};// 具体元素:电子产品
class CElectronics : public CProduct
{
public:CElectronics(const string& name, double price, int stock) : CProduct(name, price, stock) {}void Accept(CVisitor& visitor) override;
};// 访问者接口
class CVisitor
{
public:virtual ~CVisitor() {}virtual void Visit(CBook& book) = 0;virtual void Visit(CElectronics& electronics) = 0;
};// 具体访问者:计算库存总价值
class CStockValueCalculator : public CVisitor
{
public:void Visit(CBook& book) override{m_dbTotalValue += book.GetPrice() * book.GetStock();}void Visit(CElectronics& electronics) override{m_dbTotalValue += electronics.GetPrice() * electronics.GetStock();}double GetTotalValue() const { return m_dbTotalValue; }private:double m_dbTotalValue = 0.0;
};void CBook::Accept(CVisitor& visitor)
{visitor.Visit(*this);
}void CElectronics::Accept(CVisitor& visitor)
{visitor.Visit(*this);
}// 对象结构,用于管理商品集合
class CInventory
{
public:~CInventory(){for (CProduct* product : m_vctProduct){delete product;}}void AddProduct(CProduct* product){m_vctProduct.push_back(product);}void PerformCalculations(CVisitor& visitor){for (CProduct* product : m_vctProduct){product->Accept(visitor);}}private:vector<CProduct*> m_vctProduct;
};int main()
{CInventory inventory;inventory.AddProduct(new CBook("Effective C++", 50.0, 10));inventory.AddProduct(new CElectronics("Phone", 1999.99, 20));CStockValueCalculator calculator;inventory.PerformCalculations(calculator);cout << "Total stock value: " << calculator.GetTotalValue() << endl;return 0;
}

总结

        通过将算法从对象结构中分离出来,访问者模式使得每个角色(元素和访问者)都只负责自己的部分。另外,访问者模式使得添加新的操作变得容易,而不需要修改现有的类。只需创建一个新的访问者类来实现所需的操作即可,无需改动已有的元素类。

        但引入访问者模式会增加系统的设计复杂度,特别是当对象结构中有大量不同类型元素时,需要为每种类型定义相应的Visit方法,增加了代码量和理解难度。访问者需要知道所有被访问元素的具体类型和内部表示,这可能会导致访问者与元素之间产生紧密耦合,从而破坏了封装性。

相关文章:

  • Hertz+Kitex快速上手开发
  • 揭开C语言指针的神秘面纱:地址、变量与“指向”的力量
  • 【Python 元祖】 Tuple 核心知识点
  • QT单例模式简单讲解与实现
  • Redis哨兵模式,CLUSTERDOWN Hash slot not server 解决
  • 整数反转(7)
  • 《1.1_3_2 电路交换、报文交换、分组交换的性能分析|精讲篇》
  • 性能优化关键:link、script和meta的正确打开方式
  • 网络基础学习
  • 【Linux网络】UDP套接字【实现英汉转化】
  • 探索容器技术:Docker与Kubernetes的实践指南
  • ​​IIS文件上传漏洞绕过:深入解析与高效防御​
  • 关于PHP的详细介绍,结合其核心特点、应用场景及2025年的技术发展趋势,以清晰的结构呈现:
  • TCP 的三次握手
  • 构造题(Constructive Problem)
  • 历年福州大学保研上机真题
  • 【论文阅读】KIMI-VL TECHNICAL REPORT
  • C语言中的寄存器:理解与应用
  • 2025年渗透测试面试题总结-匿名[实习]安全工程师(大厂) (2)(题目+回答)
  • OpenGL Chan视频学习-6 How Shaders Work in OpenGL
  • 专业做网站的团队推荐/网页生成
  • 网站更新维护/社群推广平台
  • 上海opencart网站建设/网站推广的具体方案
  • 响应式购物网站模板/正规营销培训
  • 手机wap网站制作/清博舆情系统
  • 让别人做网站的步骤/怎么引流怎么推广自己的产品