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

参看: 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、结果

最新文章

  1. 2014年---移动端webapp个人年度总结
  2. php redis 安装篇(windows 7)
  3. UVA 10405最长公共子序列
  4. oracle系统表查询
  5. java 基础
  6. Python try/except异常处理机制
  7. WPF之通过EventTrigger修改模板中元素的属性
  8. vim插件开发初步
  9. 二、有限状态机(FSM)
  10. Hadoop 配置好hive,第一次在conf能进入,第二次就不行了,怎么办?
  11. Windows下的多线程
  12. sqlserver 将多行数据查询合并为一条数据
  13. python运维开发(二十二)---JSONP、瀑布流、组合搜索、多级评论、tornado框架简介
  14. HDOJ1728 BFS【STL__queue_的应用】
  15. c语言,const被绕过
  16. Linear Regression(线性回归)(一)—LMS algorithm
  17. HTTP简单解析
  18. SourceTree 代码库管理工具
  19. Redis集群方案&lt;转&gt;
  20. 20155117王震宇实验四 Andoid开发基础实验报告

热门文章

  1. R语言与医学统计图形【4】直方图、金字塔图
  2. mysql-加密函数AES_DECRYPT函数
  3. rust shadow
  4. C/C++运行时确定字节顺序
  5. 09 eclipse配置maven环境
  6. Redis - 1 - linux中使用docker-compose安装Redis - 更新完毕
  7. FTP 文件传输服务
  8. 【Linux】【Services】任务计划、周期性任务执行
  9. Reactor之发射器(Flux、Mono)转换操作函数
  10. ES6 object.defineProperty