Visitor 模式与 boost.variant.static_visitor

visitor 模式

visitor 模式是一种将算法与对象结构分离的软件设计模式.

这个模式的基本想法如下: 首先我们拥有一个由许多对象构成的对象结构, 这些对象的类都拥有一个 accept 方法用来接受访问者对象; 访问者是一个接口, 它拥有一个 visit 方法, 这个方法对访问到的对象结构中不同类型的元素作出不同的反应; 在对象结构的一次访问过程中, 我们遍历整个对象结构, 对每一个元素都实施 accept 方法, 在每一个元素的 accept 方法中回调访问者的 visit 方法, 从而使访问者得以处理对象结构的每一个元素. 我们可以针对对象结构设计不同的实在的访问者类来完成不同的操作.

访问者模式使得我们可以在传统的单分派语言 (如 Smalltalk, Java 和 C++) 中模拟双分派技术.

传统的 visitor 模式实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include <memory>
#include <iostream>
#include <tuple>

/// original visitor pattern
class Wheel;
class Engine;
class Body;
class Car;

class CarElementVisitor
{
public:
  virtual void visit(const std::shared_ptr<Wheel>& wheel) const = 0;
  virtual void visit(const std::shared_ptr<Engine>& engine) const = 0;
  virtual void visit(const std::shared_ptr<Body>& body) const = 0;
  virtual void visit(const std::shared_ptr<Car>& car) const = 0;
};

class CarElement
{
public:
  virtual void accept(const std::shared_ptr<CarElementVisitor>& visitor) = 0;
};

class Wheel : public CarElement,
              public std::enable_shared_from_this<Wheel>
{
public:
  virtual void accept(const std::shared_ptr<CarElementVisitor>& visitor)
  {
    visitor->visit(shared_from_this());
  }
};

class Engine : public CarElement,
               public std::enable_shared_from_this<Engine>
{
public:
  virtual void accept(const std::shared_ptr<CarElementVisitor>& visitor)
  {
    visitor->visit(shared_from_this());
  }
};

class Body : public CarElement,
             public std::enable_shared_from_this<Body>
{
public:
  virtual void accept(const std::shared_ptr<CarElementVisitor>& visitor)
  {
    visitor->visit(shared_from_this());
  }
};

class Car : public CarElement,
            public std::enable_shared_from_this<Car>
{
  typedef std::tuple<std::shared_ptr<Wheel>, std::shared_ptr<Engine>, std::shared_ptr<Body> > Elements;

  template <std::size_t> class int_ {};

  template <typename Tuple, std::size_t pos>
  void visit(const std::shared_ptr<CarElementVisitor>& visitor, const Tuple& t, int_<pos>)
  {
    visitor->visit(std::get<std::tuple_size<Tuple>::value - pos>(t));
    visit(visitor, t, int_<pos - 1>());
  }

  template <typename Tuple>
  void visit(const std::shared_ptr<CarElementVisitor>& visitor, const Tuple& t, int_<1>)
  {
    visitor->visit(std::get<std::tuple_size<Tuple>::value - 1>(t));
  }

  template <typename... Args>
  void visit(const std::shared_ptr<CarElementVisitor>& visitor, const std::tuple<Args ...>& t)
  {
    visit(visitor, t, int_<sizeof...(Args)>());
  }

public:
  Car()
  {
    elements_ = std::make_tuple(std::make_shared<Wheel>(), std::make_shared<Engine>(), std::make_shared<Body>());
  }

  virtual void accept(const std::shared_ptr<CarElementVisitor>& visitor)
  {
    visit(visitor, elements_);
    visitor->visit(shared_from_this());
  }

private:

  Elements elements_;
};

class PrintVisitor : public CarElementVisitor
{
public:
  virtual void visit(const std::shared_ptr<Wheel>& wheel) const
  {
    std::cout << "void PrintVisitor::visit(std::shared_ptr<Wheel> wheel) const" << std::endl;
  }

  virtual void visit(const std::shared_ptr<Engine>& engine) const
  {
    std::cout << "void PrintVisitor::visit(std::shared_ptr<Engine> engine) const" << std::endl;
  }

  virtual void visit(const std::shared_ptr<Body>& body) const
  {
    std::cout << "void PrintVisitor::visit(std::shared_ptr<Body> body) const" << std::endl;
  }

  virtual void visit(const std::shared_ptr<Car>& car) const
  {
    std::cout << "void PrintVisitor::visit(std::shared_ptr<Car> car) const" << std::endl;
  }
};

class OtherVisitor : public CarElementVisitor
{
public:
  virtual void visit(const std::shared_ptr<Wheel>& wheel) const
  {
    std::cout << "void OtherVisitor::visit(std::shared_ptr<Wheel> wheel) const" << std::endl;
  }

  virtual void visit(const std::shared_ptr<Engine>& engine) const
  {
    std::cout << "void OtherVisitor::visit(std::shared_ptr<Engine> engine) const" << std::endl;
  }

  virtual void visit(const std::shared_ptr<Body>& body) const
  {
    std::cout << "void OtherVisitor::visit(std::shared_ptr<Body> body) const" << std::endl;
  }

  virtual void visit(const std::shared_ptr<Car>& car) const
  {
    std::cout << "void OtherVisitor::visit(std::shared_ptr<Car> car) const" << std::endl;
  }
};

int main()
{
  std::shared_ptr<CarElement> car(std::make_shared<Car>());
  car->accept(std::make_shared<PrintVisitor>());
  car->accept(std::make_shared<OtherVisitor>());
  return 0;
}

boost.variant.static_visitor 的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <iostream>
#include <boost/variant.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/apply_visitor.hpp>

class Wheel {};
class Engine {};
class Body {};
class Car {};

/// boost static visitor

typedef boost::variant<Wheel, Engine, Body, Car> CarElement;

class PrintVisitor : public boost::static_visitor<void>
{
public:
  void operator()(const Wheel& wheel) const
  {
    std::cout << "void PrintStaticVisitor::operator()(const Wheel&) const" << std::endl;
  }

  void operator()(const Engine& engine) const
  {
    std::cout << "void PrintStaticVisitor::operator()(const Engine&) const" << std::endl;
  }

  void operator()(const Body& body) const
  {
    std::cout << "void PrintStaticVisitor::operator()(const Body&) const" << std::endl;
  }

  void operator()(const Car& car) const
  {
    /// bla bla bla
    std::cout << "void PrintStaticVisitor::operator()(const Car&) const" << std::endl;
  }
};

class OtherVisitor : public boost::static_visitor<void>
{
public:
  void operator()(const Wheel& wheel) const
  {
    std::cout << "void OtherStaticVisitor::operator()(const Wheel&) const" << std::endl;
  }

  void operator()(const Engine& engine) const
  {
    std::cout << "void OtherStaticVisitor::operator()(const Engine&) const" << std::endl;
  }

  void operator()(const Body& body) const
  {
    std::cout << "void OtherStaticVisitor::operator()(const Body&) const" << std::endl;
  }

  void operator()(const Car& car) const
  {
    /// bla bla bla
    std::cout << "void OtherStaticVisitor::operator()(const Car&) const" << std::endl;
  }
};

int main()
{
  CarElement x = Car();
  PrintVisitor print_visitor;
  OtherVisitor other_visitor;
  boost::apply_visitor(print_visitor, x);
  boost::apply_visitor(other_visitor, x);

  return 0;
}

参考

Comments