Behavioral - Visitor pattern C++ implementation

In the Visitor Pattern, we use a visitor class, which changes the execution algorithm of the element class. In this way, the element's execution algorithm can change as the visitor changes. This type of design pattern is a behavioral pattern. According to the schema, the element object has accepted a visitor object so that the visitor object can handle operations on the element object.

The client stores a collection of all products, and then when the client accepts a different visitor, it actually performs the visitor's visit operation for all products.

Not recommended!

Example

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;
}

Compile and run:

$g++ -g main.cpp -o vistor -std=c++11
$./vistor 
顾客小张买书。
顾客小张挑选苹果。
收银员小杨计算书的价格。
收银员小杨给苹果过称, 然后计算价格。

Key code:There is a method in the data base class to accept visitors and pass its own reference into the visitor.

Application example:You are a guest at a friend's house. You are a visitor. Your friend accepts your visit. You pass the friend's description and then make a judgment on the friend's description. This is the visitor pattern.

Advantages: 1. Comply with the single responsibility principle. 2. Excellent scalability. 3. Flexibility.

Disadvantages: 1. Specific elements disclose details to visitors, which violates the Dimit Principle. 2. It is difficult to change specific elements. 3. It violates the principle of dependency inversion and relies on concrete classes instead of abstractions.

Usage scenarios: 1. The class corresponding to the object in the object structure rarely changes, but it is often necessary to define new operations on this object structure. 2. Many different and unrelated operations need to be performed on the objects in an object structure, and you need to avoid letting these operations "pollute" the classes of these objects, and you do not want to modify these classes when adding new operations.

Guess you like

Origin blog.csdn.net/weixin_36389889/article/details/130972827