在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。
client存储所有product的集合,然后client当accept不同的访问者visitor时,实际执行的是该visitor对所有product的visit操作。
不太建议使用!
实例
Visitor.h
#ifndef VISTOR_H_
#define VISTOR_H_
#include <string>
class Apple;
class Book;
// 抽象访问者
class Vistor {
public:
void set_name(std::string name) {
name_ = name;
}
virtual void visit(Apple *apple) = 0;
virtual void visit(Book *book) = 0;
protected:
std::string name_;
};
#endif // VISTOR_H_
ConcreteVisitor.h
#ifndef CONCRETE_VISTOR_H_
#define CONCRETE_VISTOR_H_
#include <iostream>
#include "Visitor.h"
// 具体访问者类: 顾客
class Customer : public Vistor {
public:
void visit(Apple *apple) {
std::cout << "顾客" << name_ << "挑选苹果。" << std::endl;
}
void visit(Book *book) {
std::cout << "顾客" << name_ << "买书。" << std::endl;
}
};
// 具体访问者类: 收银员
class Saler : public Vistor {
public:
void visit(Apple *apple) {
std::cout << "收银员" << name_ << "给苹果过称, 然后计算价格。" << std::endl;
}
void visit(Book *book) {
std::cout << "收银员" << name_ << "计算书的价格。" << std::endl;
}
};
#endif // CONCRETE_VISTOR_H_
Element.h
#ifndef ELEMENT_H_
#define ELEMENT_H_
#include "Visitor.h"
// 抽象元素类
class Product {
public:
virtual void accept(Vistor *vistor) = 0;
};
#endif // ELEMENT_H_
ConcreteElement.h
#ifndef CONCRETE_ELEMENT_H_
#define CONCRETE_ELEMENT_H_
#include "Element.h"
// 具体产品类: 苹果
class Apple : public Product {
public:
void accept(Vistor *vistor) override {
vistor->visit(this);
}
};
// 具体产品类: 书籍
class Book : public Product {
public:
void accept(Vistor *vistor) override {
vistor->visit(this);
}
};
#endif // CONCRETE_ELEMENT_H_
Client.h
#ifndef CLIENT_H_
#define CLIENT_H_
#include <list>
#include "Visitor.h"
#include "Element.h"
// 购物车
class ShoppingCart {
public:
void accept(Vistor *vistor) {
for (auto prd : prd_list_) {
prd->accept(vistor);
}
}
void addProduct(Product *product) {
prd_list_.push_back(product);
}
void removeProduct(Product *product) {
prd_list_.remove(product);
}
private:
std::list<Product*> prd_list_;
};
#endif // CLIENT_H_
main.cpp
#include "Client.h"
#include "ConcreteElement.h"
#include "ConcreteVisitor.h"
int main() {
Book book;
Apple apple;
ShoppingCart basket;
basket.addProduct(&book);
basket.addProduct(&apple);
Customer customer;
customer.set_name("小张");
basket.accept(&customer);
Saler saler;
saler.set_name("小杨");
basket.accept(&saler);
return 0;
}
编译运行:
$g++ -g main.cpp -o vistor -std=c++11
$./vistor
顾客小张买书。
顾客小张挑选苹果。
收银员小杨计算书的价格。
收银员小杨给苹果过称, 然后计算价格。
关键代码:在数据基础类里面有一个方法接受访问者,将自身引用传入访问者。
应用实例:您在朋友家做客,您是访问者,朋友接受您的访问,您通过朋友的描述,然后对朋友的描述做出一个判断,这就是访问者模式。
优点: 1、符合单一职责原则。 2、优秀的扩展性。 3、灵活性。
缺点: 1、具体元素对访问者公布细节,违反了迪米特原则。 2、具体元素变更比较困难。 3、违反了依赖倒置原则,依赖了具体类,没有依赖抽象。
使用场景: 1、对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。 2、需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。