访问者模式: 封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作
首先我们拥有一个由许多对象构成的对象结构,这些对象的类(Book)都拥有一个accept方法用来接受访问者对象;
访问者(IBookVisitor)是一个接口,它拥有一个visit方法,
这个方法对访问到的对象结构中不同类型的元素作出不同的反应;
在对象结构的一次访问过程中,我们遍历整个对象结构,对每一个元素都实施accept方法,
在每一个元素的accept方法中回调访问者的visit方法,从而使访问者得以处理对象结构的每一个元素。
我们可以针对对象结构设计不同的实在的访问者类来完成不同的操作。
优点:
(1)访问者模式使得增加新的操作变得很容易。
如果一些操作依赖于一个复杂的结构对象的话,那么一般而言,增加新的操作会很复杂。
而使用访问者模式,增加新的操作就意味着增加一个新的访问者类,因此,变得很容易。
(2)访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中
缺点:
(1)访问者角色不适合具体元素角色经常发生变化的情况。(.e.g 增加新具体元素类,访问者接口就需要改变了)
(2)访问者角色要执行与元素角色相关的操作,就必须让元素角色将自己内部属性暴露出来,这就破坏了元素角色的封装性。
访问者和被访问的对象的耦合性很大
#include <iostream>
#include <stdio.h>
#include <string>
#include <vector>
using namespace std;
class Book;
class IBookVisitor
{
public:
virtual void visit(Book *book) = 0;
virtual ~IBookVisitor() {}
};
class IBook
{
public:
virtual void accept(IBookVisitor *visitor) = 0;
virtual ~IBook() { }
};
class Book : public IBook
{
public:
Book(string name) : name_(name)
{}
string getName() const
{
return name_;
}
void accept(IBookVisitor *visitor)
{
visitor->visit(this);
}
private:
string name_;
};
class Library : public IBook
{
public:
Library()
{
char name[32] = "";
IBook *book = NULL;
for (int i = 0; i < 10; ++i)
{
sprintf(name, "Book %d", i);
book = new Book(name);
pool.push_back(book);
}
}
~Library()
{
int size = pool.size();
for (int i = 0; i < size; ++i)
{
delete pool[i];
pool[i] = NULL;
}
pool.clear();
}
void accept(IBookVisitor *visitor)
{
for (vector<IBook *>::iterator it = pool.begin(); it != pool.end(); ++it)
(*it)->accept(visitor);
}
private:
vector<IBook *> pool;
};
class Student : public IBookVisitor
{
public:
void visit(Book *book)
{
cout << "Visiting " << book->getName() << endl;
}
};
int main()
{
Student student;
Library library;
library.accept(&student);
return 0;
}