欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

简单易懂23种设计模式——访问者模式【含C++代码实例】

程序员文章站 2022-06-13 14:27:33
...

23种设计模式C++实现——访问者模式

   在做面向对象的软件开发时我们往往想达到更高的代码可复用性和更合理的软件颗粒度。
  根据《设计模式——可复用面向对象软件的基础》所说:“你必须找到相关的对象,以适当的颗粒度将他们回归类,再定义类的接口和继承层次,建立对象之间的基本关系。你的设计应该对手头的问题有针对性,同时对将来的问题和需求也要有足够的通用性。12345
  内行的设计者知道:不是解决任何问题都要从头做起。他们更愿意复用以前使用的解决方案。这些重复的模式方案解决特定的问题,使得面向对象的设计更灵活、优雅,最终复用性更好。它们帮助设计者将新的设计建立在以往的工作基础上,复用以往的成功设计方案。一个熟悉这些设计模式的设计者不需要再去发现它们,而能够立即将他们应用于设计问题中。
  本系列文章主要参考文献为——设计模式,可复用面向对象软件的基础(Design Patterns Elements of Reusable Object-Oriented SoftWare Erich.),内部代码基本用C++语言编写。
  汇总链接:23种设计模式C++实现——概要(索引汇总)

摘要

本章主要说明访问者模式,该设计模式主要意图是:作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式。它将对数据的操作与数据结构进行分离,是行为类模式中最复杂的一种模式。

访问者模式确实花了很多时间理解才综合出一个感觉比较好理解的例子,文后有一些博主在这个过程中检索的文章可以参考。

主要参与者

该设计模式的参与者有5个,分别是:

  1. AbstractVisitor 抽象访问者,定义访问具体元素visit**的接口
  2. AbstractElement 抽象元素,声明一个接受操作的accept接口
  3. ConcreteVisitor(Doctor Chef)访问者实例,实现抽象访问者中声明的访问操作
  4. ConcreteElement(Hospital Resteraunt)元素实例,实现抽象元素提供的accept操作,通常是visitor.visit**(this)
  5. Client 用户

优缺点

优点

  1. 扩展性好。能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
  2. 复用性好。可以通过访问者来定义整个对象结构通用的功能,从而提高系统的复用程度。
  3. 灵活性好。访问者模式将数据结构与作用于结构上的操作解耦,使得操作集合可相对*地演化而不影响系统的数据结构。
  4. 符合单一职责原则。访问者模式把相关的行为封装在一起,构成一个访问者,使每一个访问者的功能都比较单一。

缺点

  1. 增加新的元素类很困难。在访问者模式中,每增加一个新的元素类,都要在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”。
  2. 破坏封装。访问者模式中具体元素对访问者公布细节,这破坏了对象的封装性。

具体实现代码

这里实现一个不同职业的人去医院和餐厅的例子来说明访问者模式,在小镇上有一个医院和一个餐厅,每天都会有不同的人访问这两个地方,由于访问者不同到这两个地方要做的事也有区别。医生去医院是为了工作给病人看病,厨师去医院是为了检查身体,医生去餐厅是为了吃饭,厨师去餐厅是为了工作给客人烹饪菜肴。当然还可以有建筑队去医院加建急救室,去餐厅做整体装潢(代码未做这一个,但是思路相同)。

综上就是一种简单的访问者模式实现实例,具体代码如下。

抽象访问者(AbstractVisitor)

声明:

/****************************************************************
 Doc    :   visitor.h
 Author :   BingLee
 Date   :   2020-8-31
 Info   :   Visitor Design Patten
 https://blog.csdn.net/Bing_Lee (C)All rights reserved.
******************************************************************/
#ifndef VISITOR_H
#define VISITOR_H

#include <string>

class Hospital;
class Resteraunt;

class AbstractVisitor
{
public:
    virtual void visitHospital(Hospital *place) = 0;
    virtual void visitResteraunt(Resteraunt *place) = 0;
};

具体访问者

Doctor 医生

声明:

class Doctor : public AbstractVisitor
{
public:
    Doctor();
    virtual void visitHospital(Hospital *place);
    virtual void visitResteraunt(Resteraunt *place);
};

实现:

/****************************************************************
 Doc    :   visitor.cpp
 Author :   BingLee
 Date   :   2020-8-31
 Info   :   Visitor Design Patten
 https://blog.csdn.net/Bing_Lee (C)All rights reserved.
******************************************************************/
#include "visitor.h"
#include <stdio.h>

Doctor::Doctor()
{

}

void Doctor::visitHospital(Hospital *place)
{
    std::string str = place->getName();
    printf("Doctor visit %s for service patient.\n", str.c_str());
}

void Doctor::visitResteraunt(Resteraunt *place)
{
    std::string str = place->getName();
    printf("Doctor visit %s to eat a meal.\n", str.c_str());
}

Chef 大厨

声明:

class Chef : public AbstractVisitor
{
public:
    Chef();
    virtual void visitHospital(Hospital *place);
    virtual void visitResteraunt(Resteraunt *place);
};

实现:

Chef::Chef()
{

}

void Chef::visitHospital(Hospital *place)
{
    std::string str = place->getName();
    printf("Chef visit %s get medical advice.\n", str.c_str());
}

void Chef::visitResteraunt(Resteraunt *place)
{
    std::string str = place->getName();
    printf("Chef visit %s for cooking.\n", str.c_str());
}

抽象元素(AbstractElement)

声明:

class AbstractElement
{
public:
    AbstractElement ();
    std::string getName();
    virtual void accept(AbstractVisitor *visitor) = 0;
protected:
    std::string m_name;
};

实现:

AbstractElement ::AbstractElement ()
{

}

std::string AbstractElement ::getName()
{
    return m_name;
}

具体元素

Hospital 医院

声明

class Hospital : public AbstractElement
{
public:
    Hospital();
    virtual void accept(AbstractVisitor *visitor);
};

实现

Hospital::Hospital()
{
    m_name = "Hospital No.1";
}

void Hospital::accept(AbstractVisitor *visitor)
{
    visitor->visitHospital(this);
}

Resteraunt 餐厅

声明

class Resteraunt : public AbstractElement
{
public:
    Resteraunt();
    virtual void accept(AbstractVisitor *visitor);
};

#endif // VISITOR_H

实现

Resteraunt::Resteraunt()
{
    m_name = "Resteraunt No.1";
}

void Resteraunt::accept(AbstractVisitor *visitor)
{
    visitor->visitResteraunt(this);
}

用户(Client)

/****************************************************************
 Doc    :   main.cpp
 Author :   BingLee
 Date   :   2020-8-31
 Info   :   Visitor Design Patten
 https://blog.csdn.net/Bing_Lee (C)All rights reserved.
******************************************************************/
#include <QCoreApplication>

#include "visitor.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Hospital *hospital = new Hospital();
    Resteraunt *resteraunt = new Resteraunt();

    AbstractVisitor *doctor = new Doctor();
    AbstractVisitor *chef = new Chef();

    hospital->accept(doctor);
    resteraunt->accept(doctor);

    hospital->accept(chef);
    resteraunt->accept(chef);

    return a.exec();
}

输出结果:

简单易懂23种设计模式——访问者模式【含C++代码实例】

补充说明

   通过上边这个简单的例子希望能说明什么是访问者模式(Visitor)。如果需要专栏所有设计模式的源代码请留言留下你的联系方式,若能点赞、关注就更棒了!!!

本篇博客中的代码均已通过编译,如有Bug,请提出宝贵意见~

注:文章内函数可以把除Client对象的声明放在一个头文件中,实现放在一个文件中,Client文件放在主函数中执行。

参考:


  1. 《设计模式——可复用面向对象软件的基础 》 ↩︎

  2. Github design-patterns-for-humans ↩︎

  3. https://www.runoob.com/design-pattern/visitor-pattern.html ↩︎

  4. http://c.biancheng.net/view/1397.html ↩︎

  5. JAVA设计模式之 访问者模式【Visitor Pattern】 ↩︎