【重读设计模式】访问者模式

访问者模式是设计模式中较为复杂的模式之一,而就我来看理解该模式就需要费点劲。像责任链、备忘录、中介模式这种顾名思义就能知道了解该模式是怎么做的不一样,访问者模式的设计不太容易理解,普通意义上的访问者就像记者拿着记录仪在街上采访行人一样,记者就是访问者模式中的访问者,而行人就是元素。在访问者模式中,访问者更像被访问对象在遇到访问者之后做出的反应,比如这里记者提出的问题,而访问者就是被采访的人。下面就具体的来看看访问者模式。


定义:表示作用于某个对象结构中的个元素的操作,它可以在不改变个元素的类的前提下定义作用于这些类的新操作。

定义解释:某一个对象结构中有很多个类型相同的元素(比如一个列表,或者几个相同类型的对象),现在需要对这些元素新增新的操作,一般实现是需要在抽象类中新增抽象接口,然后由各个实现实现自己各自的新操作。这破坏了类的对修改关闭的原则。访问者模式,可以在不修改类的实现的前提下,为元素新增新的操作。


类图:



模式角色:

1、抽象访问者:访问者抽象接口,通过visit(Element)方法访问Element(数据结构),完成对Element的操作行为。

2、具体访问者: 访问者的具体实现类。

3、元素:也就是被访问者,通过accept(Visitor)方法接受Visitor的访问。

4、具体元素:元素的具体实现类。
5、对象结构:拥有一组元素的组合对象。ObjectStructure本身也可以作为被访问者。


例子:

男人和女人对于不同问题的看法问题是访问者模式的合适例子,比如对于成功的看法,男人觉得成功是获得一种社会认同感,女人觉的成功就是家庭幸福。男人觉得失败就是社会不认同没有钱,女人觉得失败是婚姻不幸福,女儿不幸福。对于事业,男人认为高于家庭,女人认为低于家庭等。这里男人和女人就是元素,而成功、失败、事业就是访问者,元素对于每个访问者都需要有自己的实现,甚至于新增访问者,比如新增对于金钱的看法,男人认为那是能力的表现,女人认为那是购买力。


设计:这里有两种人,男人和女人,而且一般不会发生变化,同时有很多个问题,成功  失败  事业  金钱等甚至更多。这种元素的个数不发生变化,而问题的个数不断发生变化的情况就是访问者模式需要解决的问题。

我们将人定义为抽象元素类,男人和女人就是具体的元素,都必须实现人的visit方法(就某个问题访问了),我们定义问题的抽象类problem并提供accept抽象方法,并且有success fail career money等实现类,这里problem就是抽象访问者类,而success fail career money就是具体的访问者类,具体的访问者类必须实现accept方法,表示每种元素对于该问题的答案。对象结构就是一个由于男人和女人两个元素的数组。


实现:

//============================================================================
// Name        : visitor.cpp
// Author      : tester
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================


#include <iostream>
#include <vector>
using namespace std;


class Person;
class Man;
class Woman;
//visitor基类
class Problem
{
public:
~Problem(){};
virtual void visit(Man* person) = 0;
virtual void visit(Woman* person) = 0;
};


class Success : public Problem
{
public:
void visit(Man* person)
{
cout << "男人成功:获得社会认同感." << endl;
}


void visit(Woman* person)
{
cout << "女人成功:家庭幸福就是成功." << endl;
}
};


class Fail : public Problem
{
public:
void visit(Man* person)
{
cout << "男人失败:社会认同度低,不能赚钱." << endl;
}


void visit(Woman* person)
{
cout << "女人失败:婚姻失败,女儿不幸福." << endl;
}
};


class Career : public Problem
{
public:
void visit(Man* person)
{
cout << "男人事业感:高于家庭,高于其他." << endl;
}


void visit(Woman* person)
{
cout << "女人事业感:低于家庭,低于保养." << endl;
}
};


class Money : public Problem
{
public:
void visit(Man* person)
{
cout << "男人有钱:那是能力的表现,提升魅力值." << endl;
}


void visit(Woman* person)
{
cout << "女人有钱:那是身份的表芯,提升购买力." << endl;
}
};


//元素基类
class Person
{
public:
virtual ~Person(){};
virtual void accept(Problem* problem) = 0;
};


//元素具体类
class Man : public Person
{
public:
void accept(Problem* problem)
{
problem->visit(this);
}
};


//元素具体类
class Woman : public Person
{
public:
void accept(Problem* problem)
{
problem->visit(this);
}
};


class ObjectStruct
{
public:
void add_person(Person* person)
{
m_person_vec.push_back(person);
}


void answer(Problem* problem)
{
for(unsigned idx=0; idx<m_person_vec.size(); ++idx)
{
m_person_vec[idx]->accept(problem);
}
}


private:
vector<Person*> m_person_vec;
};


int main() {
cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!


ObjectStruct objstu;
Person* man = new Man;
objstu.add_person(man);


Person* woman = new Woman;
objstu.add_person(woman);


Problem* problem = new Success;
objstu.answer(problem);


problem = new Fail;
objstu.answer(problem);


problem = new Career;
objstu.answer(problem);


problem = new Money;
objstu.answer(problem);




return 0;
}

结果:

!!!Hello World!!!
男人成功:获得社会认同感.
女人成功:家庭幸福就是成功.
男人失败:社会认同度低,不能赚钱.
女人失败:婚姻失败,女儿不幸福.
男人事业感:高于家庭,高于其他.
女人事业感:低于家庭,低于保养.
男人有钱:那是能力的表现,提升魅力值.
女人有钱:那是身份的表芯,提升购买力.


总结:

访问者模式提供了一种元素个数不变,但是在不改变类的实现的情况下,动态的为对象提供操作的方法,我们知道装饰着模式也能为对象动态的添加行为,和装饰者模式不同的是,装饰着模式在原有对象上新增了新的属性,世界上改变了原有对象,而访问者模式是在元素类新增了新的处理行为,也就是让行为变宽了,并没有本身改变对象本身。另外,访问者模式是结构型模式,而装饰模式是行为模式。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值