设计模式,访问者模式:(都在干活,干的咋样呢),c++实现

访问者模式:(都在干活,干的咋样呢)

定义:封装一些作用于某些数据结构中的各个元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

类图摘自设计模式之禅:
在这里插入图片描述

Visitor:抽象访问者,通过参数声明可以访问的元素。
ConcreteVisitor:具体访问者,确定访问者访问一个类后的操作。
Element:抽象元素,声明接收哪一类访问者访问,声明accept(visitor)
ConcreteElement:实现accept(),一般是visitor.visit(this),基本上已经是一种模式。
ObjectStructure:结构对象,一般是容纳被访问者的容器。

优点
符合单一职责原则,具体元素角色负责数据的加载,visitor负责数据的展示,职责分明,各自变化不影响。

扩展性好
因为职责分明,扩展就很方便。

灵活性高
因为有了数据的访问权,自然就有千奇百怪的对外展现方式。

缺点
对访问者公布细节,访问者需要其他类提供方法和数据,不符合迪米特法则。

访问者与被访问者耦合较多,涉及到具体元素的更改会很麻烦。

破坏了依赖倒转原则,访问者依赖了具体,而非其抽象基类。

使用场景
一个对象结构包含很多类对象,它们接口不同,而需要对这些对象实施一些依赖于其具体类的操作时,迭代器依赖于抽象。

需要对一个对象结构中的对象进行很多不同且不相关的操作,而不想改变其中内容。

访问者模式是对迭代器(迭代模式,后来推出迭代器后迭代模式就没落了)的补充,解决了迭代器只能依赖抽象的缺陷。访问者模式还能用作拦截器,在混编模式中将会出现。

访问者模式扩展
统计:工资,利率,股票,基金,这些都是依赖于细节的情景

多个访问者同时存在和起作用
美术中:正视图,左视图,俯视图;
数学中:圆形表,正交表,扇形表;

访问者模式做大做强
一堆数据从几个角度分析,即数据挖掘。
数据的上切,下钻等处理,可翻看数据挖掘和商业智能的书。

通过访问者模式实现双分派

访问者模式是一种集中规整模式,特别适合于大规模重构的项目,这个阶段需求已经非常清晰,原系统功能点也已明确,通过访问者模式可以很容易的把一些功能进行梳理,达到功能集中化的目的。如一个统一的报表运算、UI展现等,还可以通过与其他模式混编建立一台自己的过滤器或者拦截器。

代码示例:hr和路人眼中同样的工作者,因实际情况和访问人员职责的不同而不同。

class IVisitor;
class PoolWorker;
class RichWorker;
class WeakWorker;
class IVisitor
{
public:
	virtual void Visit(const PoolWorker* oncreteElement) = 0;
	virtual void Visit(const RichWorker* oncreteElement) = 0;
	virtual void Visit(const WeakWorker* oncreteElement) = 0;
};

class Worker
{
public:
	virtual void doSth() = 0;
	virtual void accept(IVisitor* visitor) = 0;
};

class PoolWorker:public Worker
{
public:
	virtual void doSth()
	{
		cout << "穷人在工作" << endl;
	}

	virtual void accept(IVisitor* visitor)
	{
		visitor->Visit(this);
	}
};

class RichWorker :public Worker
{
	virtual void doSth()
	{
		cout << "富人在工作" << endl;
	}

	virtual void accept(IVisitor* visitor)
	{
		visitor->Visit(this);
	}
};

class WeakWorker :public Worker
{
	virtual void doSth()
	{
		cout << "虚弱的人在工作" << endl;
	}

	virtual void accept(IVisitor* visitor)
	{
		visitor->Visit(this);
	}
};

class HR :public IVisitor
{
public:
	virtual void Visit(const PoolWorker* oncreteElement)
	{
		cout << "HR眼中,这个人很贫穷,因此工作很努力" << endl;
	}
	virtual void Visit(const RichWorker* oncreteElement)
	{
		cout << "HR眼中,这个人比较有钱,工作情况一般" << endl;
	}
	virtual void Visit(const WeakWorker* oncreteElement)
	{
		cout << "HR眼中,这个人身体虚弱,脑子好使,适合做智力工作" << endl;
	}
};

class Passenger :public IVisitor
{
public:
	virtual void Visit(const PoolWorker* oncreteElement)
	{
		cout << "路人眼中,这个人很穷,不知道是干啥的" << endl;
	}
	virtual void Visit(const RichWorker* oncreteElement)
	{
		cout << "路人眼中,这个人比较有钱,看起来好帅啊" << endl;
	}
	virtual void Visit(const WeakWorker* oncreteElement)
	{
		cout << "路人眼中,这个人身体虚弱,一点也不强壮" << endl;
	}
};

void func()
{
	//创建所有的工人
	vector<Worker*> vecWorker;
	Worker* worker1 = new PoolWorker();
	Worker* worker2 = new PoolWorker();
	Worker* worker3 = new PoolWorker();
	Worker* worker4 = new PoolWorker();
	Worker* worker5 = new RichWorker();
	Worker* worker6 = new RichWorker();
	Worker* worker7 = new WeakWorker();
	Worker* worker8 = new WeakWorker();
	Worker* worker9 = new WeakWorker();
	worker1->doSth();
	worker2->doSth();
	worker3->doSth();
	worker4->doSth();
	worker5->doSth();
	worker6->doSth();
	worker7->doSth();
	worker8->doSth();
	worker9->doSth();
	//使用vector维护所有工人信息
	vecWorker.push_back(worker1);
	vecWorker.push_back(worker2);
	vecWorker.push_back(worker3);
	vecWorker.push_back(worker4);
	vecWorker.push_back(worker5);
	vecWorker.push_back(worker6);
	vecWorker.push_back(worker7);
	vecWorker.push_back(worker8);
	vecWorker.push_back(worker9);

	//创建两个访问者,让访问者访问vector中的工人
	HR* hr = new HR();
	Passenger* passenger = new Passenger();

	vector<Worker*>::iterator itWorker = vecWorker.begin();
	while (itWorker != vecWorker.end())
	{
		(*itWorker)->accept(hr);
		(*itWorker)->accept(passenger);
		++itWorker;
	}
}

int main()
{
	func();
	return 0;
}

在这里插入图片描述
在这个例子中,不同的Worker细节子类被同一个vector管理,如果想要访问vector中所有细节子类的信息,迭代器就行不通了,迭代器基于基类,用于访问vector中所有抽象基类的信息;需要使用访问者模式实现对细节信息的访问,同时设置多个访问者,便于从多个角度分析操作细节数据集(数据挖掘)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值