c++设计模式概述之访问者
代码写的不够规范,目的是为了缩短篇幅,实际中请注意。
参看: 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、结果