访问者模式--行为模式

1、描述

访问者是一种行为设计模式,允许你在不修改已有代码的情况下向已有类层次结构中添加新的行为。

优点:1、符合单一职责原则; 2、优秀的扩展性; 3、灵活性非常高

缺点:1、具体元素对访问者公布细节; 2、具体元素变更比较困难; 3、违背了依赖倒置原则

2、结构图

  • 抽象访问者(Visitor)声明访问者可以访问哪些元素,具体到程序中就是visit方法的参数定义哪些对象是可以被访问的。
  • 具体访问者(ConcreteVisitor)会为不同的具体元素类实现相同行为的不同版本
  • 抽象元素(Element)声明了一个方法来“接收”访问者。该方法必须有一个参数声明为访问者接口类型
  • 具体元素(ConcreteElement)必须实现接收方法,该方法的目的是根据当前元素类将其调用重定向到相应访问者的方法。
  • 结构对象(ObjectStruture)元素产生者,一般容纳在多个不同类、不同接口的容器。一般很少抽象出这个角色。

3、C++代码

#include <iostream>
#include <string>
#include <array>

//访问者接口声明了一组与元素类对应的访问方法。访问方法的签名能使访问者可以准确
//辨别出与其交互的元素的具体的类。
class ConcreteComponentA;
class ConcreteComponentB;

class Visitor {
 public:
  virtual void VisitConcreteComponentA(const ConcreteComponentA *element) const = 0;
  virtual void VisitConcreteComponentB(const ConcreteComponentB *element) const = 0;
};

//元素接口声明了一个`accept`方法,它会将访问者的基类作为一个参数。
class Component {
 public:
  virtual ~Component() {}
  virtual void Accept(Visitor *visitor) const = 0;
};


//每个具体元素类都必须以特定方式实现`accept`方法,使其能调用相应元素类的访问者方法。
class ConcreteComponentA : public Component {

  //注意我们正在调用的`visitConcreteComponentA`方法与当前类名相匹配。
  //这样我们能让访问者知晓与其交互的元素类。
 public:
  void Accept(Visitor *visitor) const override {
    visitor->VisitConcreteComponentA(this);
  }

  //具体元素类有一些并不在基类中的特殊方法。访问者类能够使用这些方法,
  //因为访问者类能够区分具体元素类。
  std::string ExclusiveMethodOfConcreteComponentA() const {
    return "A";
  }
};

class ConcreteComponentB : public Component {
  /**
   * Same here: visitConcreteComponentB => ConcreteComponentB
   */
 public:
  void Accept(Visitor *visitor) const override {
    visitor->VisitConcreteComponentB(this);
  }
  std::string SpecialMethodOfConcreteComponentB() const {
    return "B";
  }
};

//具体的访问者类实现了同一个算法的多个版本,而且该算法能与所有具体类进行交互。
//访问者模式在复杂对对象结构(例如组合树)上使用时能发挥最大作用。在这种情况下,
//它可以存储算法的一些中间状态并同时在结构中的不同对象上执行访问者方法。这可能会非常有帮助
class ConcreteVisitor1 : public Visitor {
 public:
  void VisitConcreteComponentA(const ConcreteComponentA *element) const override {
    std::cout << element->ExclusiveMethodOfConcreteComponentA() << " + ConcreteVisitor1\n";
  }

  void VisitConcreteComponentB(const ConcreteComponentB *element) const override {
    std::cout << element->SpecialMethodOfConcreteComponentB() << " + ConcreteVisitor1\n";
  }
};

class ConcreteVisitor2 : public Visitor {
 public:
  void VisitConcreteComponentA(const ConcreteComponentA *element) const override {
    std::cout << element->ExclusiveMethodOfConcreteComponentA() << " + ConcreteVisitor2\n";
  }
  void VisitConcreteComponentB(const ConcreteComponentB *element) const override {
    std::cout << element->SpecialMethodOfConcreteComponentB() << " + ConcreteVisitor2\n";
  }
};

//客户可以在不知晓具体类的情况下在一组元素上运行访问者操作。accept操作会将调用定位到
//访问者对象的相应操作上。
void ClientCode(std::array<const Component *, 2> components, Visitor *visitor) {
  // ...
  for (const Component *comp : components) {
    comp->Accept(visitor);
  }
  // ...
}

int main() {
  std::array<const Component *, 2> components = {new ConcreteComponentA, new ConcreteComponentB};
  std::cout << "The client code works with all visitors via the base Visitor interface:\n";
  ConcreteVisitor1 *visitor1 = new ConcreteVisitor1;
  ClientCode(components, visitor1);
  std::cout << "\n";
  std::cout << "It allows the same client code to work with different types of visitors:\n";
  ConcreteVisitor2 *visitor2 = new ConcreteVisitor2;
  ClientCode(components, visitor2);

  for (const Component *comp : components) {
    delete comp;
  }
  delete visitor1;
  delete visitor2;

  return 0;
}

参考

https://refactoringguru.cn/

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页