访问者模式:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
我们使用男人和女人在成功和失败时的不同表现举例子:
#ifndef PERSONSTATE
#define PERSONSTATE
#include <QtDebug>
#include <QString>
#include <QList>
class Man;
class Woman;
class Action
{
public:
virtual void getManConclusion(Man *concreteElementA) = 0;
virtual void getWomanConclusion(Woman *concreteElementB) = 0;
virtual QString getName(){return _name;}
virtual ~Action() = default;
private:
QString _name;
};
class Person
{
public:
virtual void Accept(Action *visitor) = 0;
virtual QString getName(){return _name;}
private:
QString _name;
};
class Success final : public Action
{
public:
void getManConclusion(Man *concreteElementA) override;
void getWomanConclusion(Woman *concreteElementB) override;
QString getName() override {return _name;} //注意:虽然子类和父类这个函数样子一样,但是必须重写,否则返回的是父类的_name!!
private:
QString _name = "成功";
};
class Failing final : public Action
{
public:
void getManConclusion(Man *concreteElementA) override;
void getWomanConclusion(Woman *concreteElementB) override;
QString getName() override {return _name;}
private:
QString _name = "失败";
};
class Amativeness final : public Action
{
public:
void getManConclusion(Man *concreteElementA) override;
void getWomanConclusion(Woman *concreteElementB) override;
QString getName() override {return _name;}
private:
QString _name = "恋爱";
};
class Man final : public Person
{
public:
void Accept(Action *visitor)
{
visitor->getManConclusion(this);
}
QString getName() override {return _name;}
private:
QString _name = "男人";
};
class Woman:public Person
{
public:
void Accept(Action *visitor)
{
visitor->getWomanConclusion(this);
}
QString getName() override {return _name;}
private:
QString _name = "女人";
};
class ObjectStructure
{
public:
void Attach(Person *p){_elements.append(QSharedPointer<Person>(p));}
void Detach(Person *p)
{
foreach (auto iterator, _elements)
{
if(iterator.data() == p)
{
_elements.removeOne(iterator); //QSharedPointer实现了operator==()函数,因此可以这样用。
break;
}
}
}
void Display(Action *a)
{
for(auto e :_elements)
{
e->Accept(a);
}
}
private:
QList<QSharedPointer<Person>> _elements;
};
#endif // PERSONSTATE
#include "personstate.h"
void Success::getManConclusion(Man *concreteElementA)
{
qDebug()<<concreteElementA->getName()<<getName()<<"时,背后多半有一个伟大的女人!";
}
void Success::getWomanConclusion(Woman *concreteElementB)
{
qDebug()<<concreteElementB->getName()<<getName()<<"时,背后多半有一个不成功的男人!";
}
void Failing::getManConclusion(Man *concreteElementA)
{
qDebug()<<concreteElementA->getName()<<getName()<<"时,闷头喝酒,谁也不用劝!";
}
void Failing::getWomanConclusion(Woman *concreteElementB)
{
qDebug()<<concreteElementB->getName()<<getName()<<"时,泪眼汪汪,谁也劝不了!";
}
void Amativeness::getManConclusion(Man *concreteElementA)
{
qDebug()<<concreteElementA->getName()<<getName()<<"时,凡事不懂也要装懂!";
}
void Amativeness::getWomanConclusion(Woman *concreteElementB)
{
qDebug()<<concreteElementB->getName()<<getName()<<"时,遇事懂装作不懂!";
}
有了人的抽象,和不同情况下动作的抽象,即可在main函数中这样举例:
#include "personstate.h"
#include <QtDebug>
int main()
{
ObjectStructure *o = new ObjectStructure();
Man *a = new Man();
Woman *b = new Woman();
o->Attach(a);
o->Attach(b);
//成功时的反应
Success *v = new Success;
o->Display(v);
//失败时 的反应
Failing *f = new Failing;
o->Display(f);
//恋爱时的反应
Amativeness *am = new Amativeness;
o->Display(am);
//结婚时的反应
Marriage *m = new Marriage;
o->Display(m);
return 0;
}
由代码可以看出,代码关键在于人只分为男人和女人,这个性别分类是稳定的,因此可以在状态类中增加“男人反应”和“女人反应”两个方法,方法的个数就稳定。而人的抽象类中有一个抽象方法“接受”,它用来获得“状态”对象这个访问者。每一个具体状态实现对于不同性别的人对应的两个方法。这样就实现了访问者模式。
最后放上源码地址:https://github.com/Dongzhixiao/designMode_qt/tree/master/menAndWomen_Visitor_pattern_28