这是大话设计模式中的访问者模式的c++版本
/*
* visitor.cpp
*
* Created on: Nov 16, 2017
* Author: clh01s@163.com
* 访问者模式:表示一个作用于某对象结构中的各个元素的操作。
* 它使你可以在不改变各个元素的类的前提下定义
* 作用于这些元素的新操作。
*/
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Man;
class Woman;
//状态的抽象类
class Action
{
public:
virtual ~Action(){}
virtual void GetManConclusion(Man* concreteElement)=0;
virtual void GetWomanConclusion(Woman* concreteElement)=0;
};
//男人女人的抽象类
class Person
{
public:
virtual ~Person(){}
//获得状态对象
virtual void Accept(Action* visitor)=0;
};
class Man:public Person
{
public:
//实现基类虚函数
void Accept(Action* visitor) override
{
/* 首先在客户程序中将具体状态作为参数传递给
* “男人”类完成了一次分派,然后“男人”类调
* 用作为参数的“具体状态”中的方法“男人反应”
* 同时将自己(this)作为参数传递进去,完成
* 了二次分派。
*/
visitor->GetManConclusion(this);
}
string GetGender(){return _gender;}
private:
string _gender = "男人";
};
class Woman:public Person
{
public:
//实现基类虚函数
void Accept(Action* visitor) override
{
visitor->GetWomanConclusion(this);
}
string GetGender(){return _gender;}
private:
string _gender = "女人";
};
//成功
class Success:public Action
{
public:
void GetManConclusion(Man* concreteElement) override
{
cout<<concreteElement->GetGender()<<"成功时,背后多半有个伟大的女人。"<<endl;
}
void GetWomanConclusion(Woman* concreteElement) override
{
cout<<concreteElement->GetGender()<<"成功时,背后多半有个不成功的男人。"<<endl;
}
};
//失败
class Failing:public Action
{
public:
void GetManConclusion(Man* concreteElement) override
{
cout<<concreteElement->GetGender()<<"失败时,闷头喝酒,谁也不用劝。"<<endl;
}
void GetWomanConclusion(Woman* concreteElement) override
{
cout<<concreteElement->GetGender()<<"失败时,两眼泪汪汪,谁也劝不了。"<<endl;
}
};
//恋爱
class Amativeness:public Action
{
public:
void GetManConclusion(Man* concreteElement) override
{
cout<<concreteElement->GetGender()<<"恋爱时,不懂也要装懂。"<<endl;
}
void GetWomanConclusion(Woman* concreteElement) override
{
cout<<concreteElement->GetGender()<<"恋爱时,懂也要装不懂。"<<endl;
}
};
//婚姻
class Marriage:public Action
{
public:
void GetManConclusion(Man* concreteElement) override
{
cout<<concreteElement->GetGender()<<"结婚时,感慨道:恋爱游戏终结时,‘有妻徒刑’遥无期。"<<endl;
}
void GetWomanConclusion(Woman* concreteElement) override
{
cout<<concreteElement->GetGender()<<"结婚时,欣慰曰:爱情长跑路漫漫,婚姻保险保平安。"<<endl;
}
};
//对象结构
class ObjectStructure
{
public:
//添加
void Attach(Person* person)
{
_elements.push_back(person);
}
//删除
void Detach(Person* person)
{
if(!_elements.empty())
{
for(int i = 0;i != _elements.size();++i)
{
if(_elements[i] == person)
{
_elements.erase(_elements.begin()+i);
}
}
}else
{
cout<<"对象向量中没有元素请检查操作是否正确."<<endl;
}
}
void Display(Action* visitor)
{
//遍历向量中存放的所有元素,调用accept
for(auto i : _elements)
{
i->Accept(visitor);
}
}
private:
vector<Person*> _elements;
};
int main()
{
ObjectStructure object;
object.Attach(new Man());
object.Attach(new Woman());
//成功反应
Success* v1 = new Success();
//显示反应
object.Display(v1);
//失败反应
Failing* v2 = new Failing();
//显示反应
object.Display(v2);
//恋爱反应
Amativeness* v3 = new Amativeness();
//显示反应
object.Display(v3);
//结婚反应
Marriage* v4 = new Marriage();
//显示反应
object.Display(v4);
return 0;
}
程序输出:
clh@clh:~/testcode/设计模式$ g++ visitor.cpp -std=c++11 -g
clh@clh:~/testcode/设计模式$ ./a.out
男人成功时,背后多半有个伟大的女人。
女人成功时,背后多半有个不成功的男人。
男人失败时,闷头喝酒,谁也不用劝。
女人失败时,两眼泪汪汪,谁也劝不了。
男人恋爱时,不懂也要装懂。
女人恋爱时,懂也要装不懂。
男人结婚时,感慨道:恋爱游戏终结时,‘有妻徒刑’遥无期。
女人结婚时,欣慰曰:爱情长跑路漫漫,婚姻保险保平安。
以下内容摘抄自《设计模式》:
访问者模式适用性:
1.一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
2.需要对一个对象结构中的对象进行很多不同且不相关的操作,而你想避免让这些操作“污染”这些对象的类,visitor使得你可以将相关的操作集中起来定义在一个类中。
3.定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,者可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作比较好。
访问者模式的优点:
1.访问者模式易于增加新的操作 访问者使得增加以来于复杂对象结构的构建的操作变得更容易了。仅需增加一个新的访问者即可在一个对象结构上定义一个新的操作。相反,如果每个功能都分散在多个类智商的话,定义新的操作时必须修改每一个类。
2.访问者集中相关的操作而分离无关的操作 相关的行为不是分布在定义该对象结构的各个类上,而是集中在一个访问者中。无关行为却被分别放在它们各自的访问者子类中。这就简化了这些元素的类,也简化了在这些访问者中定义的算法。所有与它的算法相关的数据结构都可以被隐藏在访问者中。
3.访问限制少 可以访问不具有相同父类的对象。可以对一个visitor接口增加任何类型的对象,它们不必继承相同的父类。
4.积累状态 当访问者访问对象结构中的每一个元素时,它可能会积累状态。如果没有访问者,这一状态将作为额外的参数传递给进行遍历的操作,或者定义为全局变量。
访问者模式的缺点:
1.增加新的ConcreteElement类很困难 visitor模式使得难以增加新的Element的子类。每添加一个新的ConcreteElement都要visitor中添加一个新的抽象操作,并在每一个ConcretVisitor类中实现相应操作。
2.破坏封装 访问者方法嘉定ConcreteElement接口的功能足够强,足以让访问者进行它们的工作。结果时,该模式常常迫使你提供访问元素内部状态的公共操作,这可能会破坏它们的封装性。
转载请注明源地址:http://blog.csdn.net/clh01s