C ++ design patterns - Visitor Pattern

C ++ design patterns - Visitor Pattern

Reference URL: https: //www.cnblogs.com/suzhou/p/designpattern17visitor.html

intention

It represents an operation of each element of a particular role object structure. It allows you to define the role do not change the premise of the class of each element in these elements of the new operating

applicability

Use Visitor pattern under the following conditions:
a class object structure contains many objects
need to be the objects of many different unrelated operations and
objects rarely changes, often need to be modified on its operation or add
to note that is that objects and interfaces are often the result of change, it will result in the need to redefine all visitors interfaces, can lead to a high price. So this case is defined in the object class operations better.

Class Diagram

Here Insert Picture Description

cooperation

Here Insert Picture Description

Examples

Background: Suppose your computer problems, get over there to detect sale, sale must tell you disassemble detection, detection process followed by two technicians responsible for detecting different functions.
Analysis: In this example, two different functions responsible art Visitor is detected, the respective components of the computer is the elements.
Features: Computer components are fixed and will not change much, but there is no way to find out if a method of detecting a problem, then you need to increase detections. In line with the characteristics of the visitor pattern.

C ++ implementations general

#include <iostream>
#include <string>
#include <functional>
#include <map>
using namespace std;
#include <vector>

class Element;
class CPU;
class VideoCard;
class MainBoard;

class Visitor {
public:
    Visitor(std::string name) {
        visitorName = name;
    }
    virtual void visitCPU( CPU* cpu ) {};
    virtual void visitVideoCard( VideoCard* videoCard ) {};
    virtual void visitMainBoard( MainBoard* mainBoard ) {};

    std::string getName() {
        return this->visitorName;
    };
private:
    std::string visitorName;
};

class Element {
public:
    Element( std::string name ) {
        eleName = name;
    }
    virtual void accept( Visitor* visitor ) {};

    virtual std::string getName() {
        return this->eleName;
    }
private:
    std::string eleName;
};

class CPU : public Element {
public:
    CPU(std::string name) : Element(name) {}

    void accept(Visitor* visitor) {
        visitor->visitCPU(this);
    }
};

class VideoCard : public Element {
public:
    VideoCard(std::string name) : Element(name) {}

    void accept(Visitor* visitor) {
        visitor->visitVideoCard(this);
    }
};

class MainBoard : public Element {
public:
    MainBoard(std::string name) : Element(name) {}

    void accept(Visitor* visitor) {
        visitor->visitMainBoard(this);
    }
};

class CircuitDetector : public Visitor {
public:
    CircuitDetector(std::string name) : Visitor(name) {}

    // checking cpu
    void visitCPU( CPU* cpu ) {
        std::cout << Visitor::getName() << " is checking CPU's circuits.(" << cpu->getName()<<")" << std::endl;
    }

    // checking videoCard
    void visitVideoCard( VideoCard* videoCard ) {
        std::cout << Visitor::getName() << " is checking VideoCard's circuits.(" << videoCard->getName()<<")" << std::endl;
    }

    // checking mainboard
    void visitMainBoard( MainBoard* mainboard ) {
        std::cout << Visitor::getName() << " is checking MainBoard's circuits.(" << mainboard->getName() <<")" << std::endl;
    }

};

class FunctionDetector : public Visitor {
public:
    FunctionDetector(std::string name) : Visitor(name) {}
    virtual void visitCPU( CPU* cpu ) {
        std::cout << Visitor::getName() << " is check CPU's function.(" << cpu->getName() << ")"<< std::endl;
    }

    // checking videoCard
    void visitVideoCard( VideoCard* videoCard ) {
        std::cout << Visitor::getName() << " is checking VideoCard's function.(" << videoCard->getName()<< ")" << std::endl;
    }

    // checking mainboard
    void visitMainBoard( MainBoard* mainboard ) {
        std::cout << Visitor::getName() << " is checking MainBoard's function.(" << mainboard->getName() << ")"<< std::endl;
    }
};


class Computer {
public:
    Computer(CPU* cpu,
             VideoCard* videocard,
             MainBoard* mainboard) {
        elementList.push_back(cpu);
        elementList.push_back(videocard);
        elementList.push_back(mainboard);
    };
    void Accept(Visitor* visitor) {
        for( std::vector<Element*>::iterator i = elementList.begin(); i != elementList.end(); i++ )
        {
            (*i)->accept(visitor);
        }
    };
private:
    std::vector<Element*> elementList;
};

int main(){
    CPU* cpu = new CPU("Intel CPU");
    VideoCard* videocard = new VideoCard("XXX video card");
    MainBoard* mainboard = new MainBoard("HUAWEI mainboard");
    Computer* myComputer = new Computer(cpu, videocard, mainboard);

    CircuitDetector* Dan = new CircuitDetector("CircuitDetector Dan");
    FunctionDetector* Tom = new FunctionDetector("FunctionDetector Tom");

    std::cout << "\nStep 1: Dan is checking computer's circuits." << std::endl;
    myComputer->Accept(Dan);
    std::cout << "\nStep 2: Tom is checking computer's functions." << std::endl;
    myComputer->Accept(Tom);

    return 0;
}

Based on variable parameter template

GOF "Design Patterns" book is also clear that the problem of the Visitor pattern Note: the class definition object structure rarely changes, but often need to define new operations on this structure. Changes in the structure of the object class needs to redefine the interface for all visitors, which may need to pay a high price. If the object class structure often changed, or these operations is preferably defined in those classes.

In other words, the visitor is a visitor mode should be a stable succession system, if the inheritance system often changes, it will lead to frequent changes Visitor base class, as defined object types need to access in the Visitor base class, each additional access types will be a corresponding increase in pure virtual function, in the embodiment, if the need to add a new visitor is ConcreteElement3, you need to add a pure virtual function in the base class visitor:

virtual void Visit(ConcreteElement3* element) = 0;

According to the principles of programming to interfaces, we should rely on the interface and should not depend on the implementation, because the interface is stable and will not change. The Visitor pattern is not stable interfaces, which can lead to instability of the entire system, there is a big risk. To solve this problem, the most fundamental way is to define a stable Visitor interface layer that will not be adding new visitors and to modify the interface layer, the ability to define a stable Visitor interface layer it? The answer is yes, be improved by C ++ 11, we can achieve this goal.

By variable parameter template can achieve a stable interface layer, using a variable parameter template can support any number of characteristic parameters, allowing any number of visitors to the interface layer is accessible to visitors, thus eliminating the need to increase it is a new visitor to modify the interface layer, the interface layer such that the stable.

#include <iostream>
#include <string>
#include <vector>

using namespace std;

/*--------Template--------*/
template <typename... Types>
class Visitor_;
template <typename T, typename... Types>
class Visitor_<T,Types...> : Visitor_<Types...>{
public:
    using Visitor_<Types...>::Visit;//避免覆盖父类的同名方法
    virtual void Visit(T&) = 0;
};
template <typename T>
class Visitor_<T>{
public:
    virtual void Visit(T&) = 0;
};


class Element;
class CPU;
class VideoCard;
class MainBoard;
class Element;

using VisitorBase=Visitor_<CPU,VideoCard,MainBoard> ;

/*------------------*/

class Visitor : public VisitorBase {
public:
    Visitor(std::string&& name) {
        visitorName = std::forward<string>(name);
    }

    std::string getName() {
        return this->visitorName;
    };
private:
    std::string visitorName;
};


class Element {
public:
    Element( std::string&& name ) {
        eleName = std::forward<string>(name);
    }
    virtual void accept( Visitor& visitor ) {};

    virtual std::string getName() {
        return this->eleName;
    }
private:
    std::string eleName;
};

/*----------- Elements -------------*/

class CPU : public Element {
public:
    CPU(std::string name) : Element(std::move(name)) {}

    void accept(Visitor& visitor) override {
        visitor.Visit(*this);
    }
};

class VideoCard : public Element {
public:
    VideoCard(std::string name) : Element(std::move(name)) {}

    void accept(Visitor& visitor) override {
        visitor.Visit(*this);
    }
};

class MainBoard : public Element {
public:
    MainBoard(std::string name) : Element(std::move(name)) {}

    void accept(Visitor& visitor) override {
        visitor.Visit(*this);
    }
};

/*----------- ConcreteVisitor -------------*/

class CircuitDetector : public Visitor{
public:
    CircuitDetector(std::string name) : Visitor(std::move(name)) {}

    // checking cpu
    void Visit(CPU& cpu ) override {
        std::cout << Visitor::getName() << " is checking CPU's circuits.(" << cpu.getName()<<")" << std::endl;
    }

    // checking videoCard
    void Visit( VideoCard& videoCard ) override {
        std::cout << Visitor::getName() << " is checking VideoCard's circuits.(" << videoCard.getName()<<")" << std::endl;
    }

    // checking mainboard
    void Visit( MainBoard& mainboard ) override {
        std::cout << Visitor::getName() << " is checking MainBoard's circuits.(" << mainboard.getName() <<")" << std::endl;
    }

};

class FunctionDetector : public Visitor {
public:
    FunctionDetector(std::string name) : Visitor(std::move(name)) {}
    void Visit( CPU& cpu )  override {
        std::cout << Visitor::getName() << " is check CPU's function.(" << cpu.getName() << ")"<< std::endl;
    }

    // checking videoCard
    void Visit( VideoCard& videoCard ) override  {
        std::cout << Visitor::getName() << " is checking VideoCard's function.(" << videoCard.getName()<< ")" << std::endl;
    }

    // checking mainboard
    void Visit( MainBoard& mainboard ) override {
        std::cout << Visitor::getName() << " is checking MainBoard's function.(" << mainboard.getName() << ")"<< std::endl;
    }
};

/*------------------------*/
class Computer {
public:
    Computer(CPU* cpu,
             VideoCard* videocard,
             MainBoard* mainboard) {
        elementList.push_back(cpu);
        elementList.push_back(videocard);
        elementList.push_back(mainboard);
    };
    void Accept(Visitor& visitor) {
        for( std::vector<Element*>::iterator i = elementList.begin(); i != elementList.end(); i++ )
        {
            (*i)->accept(visitor);
        }
    };
private:
    std::vector<Element*> elementList;
};


int main(){
    CPU* cpu = new CPU("Intel CPU");
    VideoCard* videocard = new VideoCard("XXX video card");
    MainBoard* mainboard = new MainBoard("HUAWEI mainboard");
    Computer* myComputer = new Computer(cpu, videocard, mainboard);

    CircuitDetector* Dan = new CircuitDetector("CircuitDetector Dan");
    FunctionDetector* Tom = new FunctionDetector("FunctionDetector Tom");

    std::cout << "\nStep 1: Dan is checking computer's circuits." << std::endl;
    myComputer->Accept(*Dan);
    std::cout << "\nStep 2: Tom is checking computer's functions." << std::endl;
    myComputer->Accept(*Tom);

    return 0;
}

Published 155 original articles · won praise 15 · views 160 000 +

Guess you like

Origin blog.csdn.net/wangdamingll/article/details/104676365