访问者模式属于行为变化模式。
在GOF的《设计模式:可复用面向对象软件的基础》一书中对访问者模式是这样说的:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化。该模式的目的是要把处理从数据结构分离出来。访问者模式让增加新的操作很容易,因为增加新的操作就意味着增加一个新的访问者。访问者模式将有关的行为集中到一个访问者对象中。现在再来说说我之前经历过的那个项目。
是基于Windows Shell开发的一个项目,在一个容器中存储了很多的Shell Items,同时定义了对Items的操作,由于项目一直都在进行后期扩展,对Items的操作在后期都需要进行扩展的;而现在的做法是,定义一个操作类,该操作类中定义了一个集合,该集合存放Items,在该操作类中扩展对应的操作方法。现在想想如果使用访问者模式也是可以的,由于Items集合是固定的,当需要扩展集合的操作时,只需要添加对应的访问者即可。
使用场合
一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作;
需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。Visitor使得你可以将相关的操作集中起来定义在一个类中;
当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作;
定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。
访问者模式有如下的优点:
1,访问者模式使得增加新的操作变得很容易。如果一些操作依赖于一个复杂的结构对象的话,那么一般而言,增加新的操作会很复杂。而使用访问者模式,增加新的操作就意味着增加一个新的访问者类,因此,变得很容易。
2,访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中。
3,访问者模式可以跨过几个类的等级结构访问属于不同的等级结构的成员类。迭代子只能访问属于同一个类型等级结构的成员对象,而不能访问属于不同等级结构的对象。访问者模式可以做到这一点。
4,积累状态。每一个单独的访问者对象都集中了相关的行为,从而也就可以在访问的过程中将执行操作的状态积累在自己内部,而不是分散到很多的节点对象中。这是有益于系统维护的优点。
访问者模式有如下的缺点:
1,增加新的节点类变得很困难。每增加一个新的节点都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作。
2,破坏封装。访问者模式要求访问者对象访问并调用每一个节点对象的操 作,这隐含了一个对所有节点对象的要求:它们必须暴露一些自己的操作和内部状态。不然,访问者的访问就变得没有意义。由于访问者对象自己会积累访问操作所 需的状态,从而使这些状态不再存储在节点对象中,这也是破坏封装的。
示例代码
#include <iostream>
#include <string>
#include <list>
using namespace std;
class Element;
class Visitor
{
public:
virtual void Visit(Element *element) {};
};
// "Element"
class Element
{
public:
// Methods
virtual void Accept(Visitor *visitor) {};
};
// "ConcreteElement"
class Employee : public Element
{
public:
string name;
double income;
int vacationDays;
public:
Employee(string name, double income,
int vacationDays)
{
this->name = name;
this->income = income;
this->vacationDays = vacationDays;
}
void Accept(Visitor *visitor)
{
visitor->Visit(this);
}
};
class IncomeVisitor : public Visitor
{
public:
void Visit(Element *element)
{
Employee *employee = ((Employee*)element);
employee->income *= 1.10;
cout << employee->name << " 's new income: " << employee->income << endl;
}
};
class VacationVisitor : public Visitor
{
public:
void Visit(Element *element)
{
Employee *employee = ((Employee*)element);
// Provide 3 extra vacation days
employee->vacationDays += 3;
cout << employee->name << " 's new vacation days: " << employee->income << endl;
}
};
// "ObjectStructure"
class Employees
{
private:
list< Employee*> employees;
public:
void Attach(Employee *employee)
{
employees.push_back(employee);
}
void Detach(Employee *employee)
{
employees.remove(employee);
}
void Accept(Visitor *visitor)
{
for (std::list<Employee*>::iterator it = employees.begin(); it != employees.end(); ++it)
(*it)->Accept(visitor);
}
};
void main()
{
Employees *e = new Employees();
e->Attach(new Employee("Tom", 25000.0, 14));
e->Attach(new Employee("Thomas", 35000.0, 16));
e->Attach(new Employee("Roy", 45000.0, 21));
// Create two visitors
IncomeVisitor *v1 = new IncomeVisitor();
VacationVisitor *v2 = new VacationVisitor();
// Employees are visited
e->Accept(v1);
e->Accept(v2);
}
网友评论