访问者模式

一 使用场景
访问者模式是一种较为复杂的行为型设计模式,它包含访问者和被访问元素两个主要组成部分,这些被访问的元素通常具有不同的类型,且不同的访问者可以对它们进行不同的访问操作。

二 定义
问者模式Visitor Pattern: 提供一个作用于某对象结构中的各元素的操作表示,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式是一种对象行为型模式。
访问者模式_第1张图片
Vistor抽象访问者:抽象访问者为对象结构中每一个具体元素类ConcreteElement声明一个访问操作,从这个操作的名称或参数类型可以清楚知道需要访问的具体元素的类型,具体访问者需要实现这些操作方法,定义对这些元素的访问操作。

ConcreteVisitor具体访问者:具体访问者实现了每个由抽象访问者声明的操作,每一个操作用于访问对象结构中一种类型的元素。

Element 抽象元素:抽象元素一般是抽象类或者接口,它定义一个accept()方法,该方法通常以一个抽象访问者作为参数。

ConcreteElement 具体元素:具体元素实现了accept()方法,在accept()方法中调用访问者的访问方法以便完成对一个元素的操作。

ObjectStructure 对象结构:对象结构是一个元素的集合,它用于存放元素对象,并且提供了遍历其内部元素的方法。它可以结合组合模式来实现,也可以是一个简单的集合对象,如一个List对象或一个Set对象。

访问者模式中对象结构存储了不同类型的元素对象,以供不同访问者访问。访问者模式包括两个层次结构,一个是访问者层次结构,提供了抽象访问者和具体访问者,一个是元素层次结构,提供了抽象元素和具体元素。相同的访问者可以以不同的方式访问不同的元素,相同的元素可以接受不同访问者以不同访问方式访问。在访问者模式中,增加新的访问者无须修改原有系统,系统具有较好的可扩展性。

三 C++实现
Visitor.h

#pragma once

#include 
#include 
#include 

using namespace std;


class CPerson;  
class CStudent;  
class CTeacher;  

class CVisitor;  
class CPrinter; 

class CPerson
{
public:
    virtual void Accept(CVisitor &) = 0;

    void setName(const std::string _name){
        name = _name;
    }

    std::string getName(){
        return name;
    }

    void setGender(int & _gender){
        gender = _gender;
    }

    int getGender(){
        return gender;
    }

protected:
    string name;
    int gender;
};

class CVisitor
{
public:
    CVisitor(){}

    virtual ~CVisitor(){}

    virtual void Visit(CStudent&) = 0;

    virtual void Visit(CTeacher&) = 0;
};

class CStudent:public CPerson
{
public:
    CStudent(std::string _name, int _gender, int _grade){
        name = _name;
        gender = _gender;
        grade = _grade;
    }

    void Accept(CVisitor & _printer){
        _printer.Visit(*this);
    }

    void setGrade(int _grade){
        grade = _grade;
    }

    int getGrade(){
        return grade;
    }

private:
    int grade;

};


class CTeacher:public CPerson
{
public:
    CTeacher(std::string _name, int _gender, int _time){
        name = _name;
        gender = _gender;
        service_time = _time;
    }

    virtual ~CTeacher(){}

    void Accept(CVisitor& printer){
        printer.Visit(*this);
    }

    void setServiceTime(int _time){
        service_time = _time;
    }

    int getServiceTime(){
        return service_time;
    }


private:
    int service_time;
};


class CPrinter:public CVisitor
{
public:
    void Visit(CStudent& s){
        std::cout << "student:" << std::endl;
        std::cout << "\t Name:" << s.getName() << std::endl;
        std::cout << "\t gender:" << s.getGender() << std::endl;
        std::cout << "\t grade:" << s.getGrade() << std::endl;
    }

    void Visit(CTeacher& t){
        std::cout << "teacher:" << std::endl;
        std::cout << "\t Name:" << t.getName() << std::endl;
        std::cout << "\t gender:" << t.getGender() << std::endl;
        std::cout << "\t time:" << t.getServiceTime() << std::endl;
    }
};


class Organization
{
public:
    Organization(){}

    virtual ~Organization(){
        MList::iterator ite = person_list.begin();
        for(;ite!=person_list.end();ite++){
            delete *ite;
            *ite = NULL;
        }
    }

    void addPerson(CPerson * person){
        person_list.push_back(person);
    }

    void printMember(CPrinter & printer){
        MList::iterator ite = person_list.begin();
        for(;ite!=person_list.end();ite++){
            (*ite)->Accept(printer);
        }
    }

private:
    typedef list MList;
    MList person_list;
};

main.cpp

#include 

#include "Visitor.h"

using namespace std;


int main()
{
    Organization organ;
    organ.addPerson(new CTeacher("Jim", 1, 10));
    organ.addPerson(new CStudent("Peter", 1, 2));

    CPrinter printer;

    organ.printMember(printer);

    system("pause");
    return 0;
}

运行结果
访问者模式_第2张图片

四 总结
.优点
1 增加新的访问操作很方便。使用访问者模式,增加新的访问操作就意味着增加一个新的具体访问者类,实现简单,无须修改源代码,符合“开闭原则”。
2 将有关元素对象的访问行为集中到一个访问者对象中,而不是分散在一个个的元素类中。类的职责更加清晰,有利于对象结构中元素对象的复用,相同的对象结构可以供多个不同的访问者访问。
3 让用户能够在不修改现有元素类层次结构的情况下,定义作用于该层次结构的操作。

缺点
1 增加新的元素类很困难。在访问者模式中,每增加一个新的元素类都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”的要求。
2 破坏封装。访问者模式要求访问者对象访问并调用每一个元素对象的操作,这意味着元素对象有时候必须暴露一些自己的内部操作和内部状态,否则无法供访问者访问

文章是本人根据教材和网络上面的文章整理而成,供学习之用。

你可能感兴趣的:(访问者模式,设计模式,软件设计模式)