代码写的不够规范,目的是为了缩短篇幅,实际中请注意。

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

1、概述

  类比生活中的场景,购物商场中的商品、顾客、收营员。商品针对不同的人员,对商品的操作也是不同的。比如,顾客挑选商品,购买商品, 而收银员则是核对商品价格,针对商品收银。 同样是商品,但是面对不同的人,其操作也是不同的。

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

  下面以商场购物为例

2、抽象访问者类

// 顾客,抽象类
class visitor
{
public:
void set_name(std::string name) { _str_name = name; } // 访问商品
virtual void visit(bowel *pbowel) = 0;
virtual void visit(chicken *pchicken) = 0;
std::string get_name() { return _str_name; };
protected:
std::string _str_name;
};

3、抽象商品类

// 抽象商品类
class product
{
public:
virtual void accept(visitor *pvisitor) = 0;
};

4、具体产品类

  这里准备了碗和鸡肉两种商品

// 碗,一个具体的商品类
class bowel : public product
{
public:
void accept(visitor *pvisitor)
{
if (pvisitor)
pvisitor->visit(this);
}
}; // 鸡肉,一个具体的商品类
class chicken : public product
{
public:
void accept(visitor *pvisitor)
{
if (pvisitor)
pvisitor->visit(this);
}
};

5、具体的访问者

  这里实现了顾客和收银员

// 顾客A
class customerA : public visitor
{
public:
void visit(bowel *pbowel)
{
if (pbowel)
std::cout << _str_name << "正在挑选-碗\n";
} void visit(chicken *pchicken)
{
if (pchicken)
std::cout << _str_name << "正在挑选-鸡肉\n";
}
}; //收银员
class saler : public visitor
{
public:
void visit(bowel *pbowel)
{
if (pbowel)
std::cout << _str_name << "正在扫描商品-碗\n";
} void visit(chicken *pchicken)
{
if (pchicken)
std::cout << _str_name << "正在扫描商品-鸡肉\n";
}
};

6、对象结构类

  这里以购物车为例

// 购物车, 对象结构
class shopping_cart
{
public:
// 可以添加商品到购物车
void add(product *ppd)
{
if (ppd)
{
_list_product.push_back(ppd);
std::cout << "\n购物车:添加商品成功\n";
}
} // 可以从购物车删除商品
void remove(product* ppd)
{
// 1、要删除的商品不存在
if (!ppd)
{
std::cout << "\n购物车:商品删除失败,待删除的商品不存在\n";
return;
} // 2、找下,购物车是否存在该商品
std::list<product*> ::iterator& it = std::find(_list_product.begin(), _list_product.end(), ppd);
// 找到了,再删除
if (_list_product.end() != it)
{
_list_product.remove(ppd);
std::cout << "\n购物车:成功移除商品\n";
}
else
std::cout << "\n购物车:删除商品失败,没有找到该商品\n";
} void accept(visitor *pvisitor)
{
if (!pvisitor)
return; for each(auto item in _list_product)
{
item->accept(pvisitor);
}
} private:
// 购物车,可以存放很多商品,
std::list<product*> _list_product;
};

7、调用

void call_visitor()
{
// 1、商场准备上架商品
bowel bw1;
bowel bw2; chicken ck1;
chicken ck2; // 2、再给客户准备购物车,方便购物
shopping_cart sc; // 消费者A + 商场服务对象
customerA customa;
customa.set_name(std::string("顾客A"));
saler salerZ;
salerZ.set_name(std::string("收银员Z")); // 3、顾客挑选商品
// 3.1、顾客需要购物车
sc.accept(&customa);
// 3.2、将选好的商品放入购物车
std::cout << "\n---------------------------------\n";
customa.visit(&bw1);
sc.add(&bw1); std::cout << "\n---------------------------------\n";
customa.visit(&bw2);
sc.add(&bw2); std::cout << "\n---------------------------------\n";
sc.add(&ck1);
customa.visit(&ck1); std::cout << "\n---------------------------------\n";
sc.add(&ck2);
customa.visit(&ck2);
std::cout << "\n---------------------------------\n"; // 4、商品买多了? 移除
std::cout << customa.get_name() << "\n正在移除商品\n";
sc.remove(&ck2); std::cout << "\n-------------------------\n选购结束,准备结算:\n";
// 5、这时,购物车是由收银员check
sc.accept(&salerZ);
}

8、结果

c++设计模式概述之访问者的更多相关文章

  1. 设计模式 ( 二十 ) 访问者模式Visitor(对象行为型)

    设计模式 ( 二十 ) 访问者模式Visitor(对象行为型) 1.概述 在软件开发过程中,对于系统中的某些对象,它们存储在同一个集合collection中,且具有不同的类型,而且对于该集合中的对象, ...

  2. OOAD-设计模式(二)之GRASP模式与GOF设计模式概述

    一.GRASP模式(通用责任分配软件模式)概述 1.1.理解责任 1)什么是责任 责任是类间的一种合约或义务,也可以理解成一个业务功能,包括行为.数据.对象的创建等 知道责任——表示知道什么 行为责任 ...

  3. PHP设计模式概述

    PHP设计模式概述 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. ...

  4. java设计模式概述

    java的设计模式大体上分为三大类: 创建型模式(5种):工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式. 结构型模式(7种):适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组合模 ...

  5. 23种GoF设计模式概述

    23种GoF设计模式概述 在前面,我们对 GoF 的 23 种设计模式进行了分类,这里先对各个设计模式的功能进行简要介绍,以便有个大概了解.后面的章节再进行详细介绍. 创建型模式 关注于怎么创建对象的 ...

  6. Java设计模式(一):设计模式概述、UML图、设计原则

    1 设计模式概述 1.1 软件设计模式的产生背景 "设计模式"最初并不是出现在软件设计中,而是被用于建筑领域的设计中. 1977年美国著名建筑大师.加利福尼亚大学伯克利分校环境结构 ...

  7. 设计模式(一)----设计模式概述及UML图解析

    1.设计模式概述 1.1 软件设计模式的产生背景 "设计模式"最初并不是出现在软件设计中,而是被用于建筑领域的设计中. 1977年美国著名建筑大师.加利福尼亚大学伯克利分校环境结构 ...

  8. java 28 - 1 设计模式 之 面向对象思想设计原则和模版设计模式概述

    在之前的java 23 中,了解过设计模式的单例模式和工厂模式.在这里,介绍下设计模式 面向对象思想设计原则 在实际的开发中,我们要想更深入的了解面向对象思想,就必须熟悉前人总结过的面向对象的思想的设 ...

  9. 重学 Java 设计模式:实战访问者模式「模拟家长与校长,对学生和老师的不同视角信息的访问场景」

    作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 能力,是你前行的最大保障 年龄会不断的增长,但是什么才能让你不 ...

随机推荐

  1. JSOI2021 游记

    Day 0 - 2021.4.9 写一波最近的事情吧( 3 月 20 号出头 cnblogs 抽风,说 25 号恢复来着,我就囤了一堆博客在本地准备 25 号发,结果到时候就懒得动了.干脆越屯越多,省 ...

  2. intent.getSerializableExtra(转)

    Activity之间通过Intent传递值,支持基本数据类型和String对象及它们的数组对象byte.byte[].char.char[].boolean.boolean[].short.short ...

  3. 【R】行或列数目不同的两个数据框如何用rbind/cbind合并?

    目录 前言 方法一:dplyr的bind_rows 方法二:plyr的rbind.fill 前言 通常我们用rbind和cbind合并相同行列的数据框.当两个数据框具有不同行列数目时,直接用会报错. ...

  4. 【GS模型】全基因组选择之rrBLUP

    目录 1. 理论 2. 实操 2.1 rrBLUP包简介 2.2 实操 3. 补充说明 关于模型 关于交叉验证 参考资料 1. 理论 rrBLUP是基因组选择最常用的模型之一,也是间接法模型的代表.回 ...

  5. Nginx 动态增加扩展

    Nginx 动态增加扩展 1. 先查看目前nginx已加载模块 /home/nginx-1.18.0 # nginx -V nginx version: nginx/1.18.0 built by g ...

  6. jenkins原理简析

    持续集成Continuous Integration(CI) 原理图: Gitlab作为git server.Gitlab的功能和Github差不多,但是是开源的,可以用来搭建私有git server ...

  7. 34. Swap Nodes in Pairs

    Swap Nodes in Pairs My Submissions QuestionEditorial Solution Total Accepted: 95230 Total Submission ...

  8. k8s集群中部署Rook-Ceph高可用集群

    先决条件 为确保您有一个准备就绪的 Kubernetes 集群Rook,您可以按照这些说明进行操作. 为了配置 Ceph 存储集群,至少需要以下本地存储选项之一: 原始设备(无分区或格式化文件系统) ...

  9. C++中Try Catch中的继承

    1.C++中Try Catch简介:我们编译运行程序出错的时候,编译器就会抛出异常.抛出异常要比终止程序灵活许多. 而C++异常是指在程序运行时发生的反常行为,这些行为超出了函数正常功能的范围.当程序 ...

  10. 16. Linux find查找文件及文件夹命令

    find的主要用来查找文件,查找文件的用法我们比较熟悉,也可用它来查找文件夹,用法跟查找文件类似,只要在最后面指明查找的文件类型 -type d,如果不指定type类型,会将包含查找内容的文件和文件夹 ...