访问者模式
定义:
对象结构中对众多的元素进行访问操作,将结构分为访问者对象和元素对象
优点:
(1)增加新的访问很方便
(2)将元素的访问集中到一个访问者对象,而不是在一个个元素类中实现
缺点:
(1)增加新的元素类比较困难,需要需要具体访问者,不满足开闭原则
(2)破坏封装性,访问者对象需要对元素对象进行操作,可能会暴露元素对象内部操作和状态
使用范围:
一个对象结构包含对多个对象的访问,且每个对象有不同的访问操作
如:处方单,药房访问给药,缴费处访问交钱
结构:
visitor_pattern:访问者抽象类
hr_visitor_pattern,pd_visitor_pattern:具体访问者类
element:元素抽象类
a_element,b_element:具体元素类
element_list:元素集合类,负责传入访问者实现元素类的方法回调
实现:
namespace behavioral_pattern
{
class visitor_pattern;
class element
{
public:
virtual void accept(std::weak_ptr<visitor_pattern> v) {};
void set(std::string s) { this->str = s; }
std::string get() { return str; }
private:
std::string str;
};
class a_element : public element{ void accept(std::weak_ptr<visitor_pattern> v); };
class b_element : public element{ void accept(std::weak_ptr<visitor_pattern> v); };
class visitor_pattern
{
public:
virtual void visit(a_element ele) = 0;
virtual void visit(b_element ele) = 0;
};
class hr_visitor_pattern : public visitor_pattern
{
virtual void visit(a_element ele);
virtual void visit(b_element ele);
};
class pd_visitor_pattern : public visitor_pattern
{
virtual void visit(a_element ele);
virtual void visit(b_element ele);
};
class element_list
{
public:
void insert_element(std::shared_ptr<element> e)
{
list_ele.push_back(e);
}
void do_visit(std::shared_ptr<visitor_pattern> v)
{
for each(auto itr in list_ele)
{
itr.get()->accept(v);
}
}
private:
std::list<std::shared_ptr<element>> list_ele;
};
}
void a_element::accept(std::weak_ptr<visitor_pattern> v)
{
v.lock().get()->visit(*this);
}
void b_element::accept(std::weak_ptr<visitor_pattern> v)
{
v.lock().get()->visit(*this);
}
void hr_visitor_pattern::visit(a_element ele)
{
std::cout << "hr_visitor_pattern: a_element: " << ele.get().c_str() << std::endl;
}
void hr_visitor_pattern::visit(b_element ele)
{
std::cout << "hr_visitor_pattern: b_element: " << ele.get().c_str() << std::endl;
}
void pd_visitor_pattern::visit(a_element ele)
{
std::cout << "pd_visitor_pattern: a_element: " << ele.get().c_str() << std::endl;
}
void pd_visitor_pattern::visit(b_element ele)
{
std::cout << "pd_visitor_pattern: b_element: " << ele.get().c_str() << std::endl;
}
测试:
基于GoogleTest 的单元测试框架;框架可参考如下网址:
https://www.cnblogs.com/jycboy/p/gtest_catalog.html
TEST(test_visitor_pattern, success_insert_visit)
{
std::shared_ptr<element> e1{new a_element()};
e1.get()->set("aa00");
std::shared_ptr<element> e2{ new a_element() };
e2.get()->set("aa11");
std::shared_ptr<element> e3{ new b_element() };
e3.get()->set("bb22");
element_list li;
li.insert_element(e1);
li.insert_element(e2);
li.insert_element(e3);
std::shared_ptr<visitor_pattern> v{ new pd_visitor_pattern() };
li.do_visit(v);
}
总结
(1)需在客户端进行元素对象创建,并加到元素集合类中,进行元素遍历访问触发
(2)调用元素集合类的访问方法,传入访问者对象作为参数;遍历元素类实现回调方法
(3)访问者操作元素类不可对源对象进行污染