访问者模式:(都在干活,干的咋样呢)
定义:封装一些作用于某些数据结构中的各个元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
类图摘自设计模式之禅:
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中所有抽象基类的信息;需要使用访问者模式实现对细节信息的访问,同时设置多个访问者,便于从多个角度分析操作细节数据集(数据挖掘)。