• C++设计模式之代理模式(结构型模式)


    学习软件设计,向OO高手迈进!
    设计模式(Design pattern)是软件开发人员在软件开发过程中面临的一般问题的解决方案。
    这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
    是前辈大神们留下的软件设计的"招式"或是"套路"。

    什么是代理模式

    在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式,也就是说当客户端无法直接访问某个对象或访问某个对象存在困难时,可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,所访问的真实对象代理对象需要实现相同的接口。

    举例说明,就是一个人或者一个机构,代表另一个人或者另一个机构采取行动。在一些情况下,客户端不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用。

    定义

    在代理模式中,我们为其他对象提供一种代理以控制对这个真实对象的访问。

    直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的间接层,**“增加一层间接层”**是软件系统中对许多复杂问题的一种常见解决方法。

    UML类图

    在这里插入图片描述

    代理模式中的角色:

    1. Subject(抽象主题角色):真实主题与代理主题的共同接口。
    2. RealSubject(真实主题角色):定义了代理角色所代表的真实对象。也叫做被委托角色被代理角色,是业务逻辑的具体执行者。
    3. Proxy(代理主题角色):含有对真实主题角色的引用,代理角色通常在将客户端调用传递给真实主题对象之前或者之后执行某些操作,而不是单纯返回真实的对象。
    4. Client:客户类,使用代理对象的类。

    Version 1.0

    下面我们以送女朋友礼物来讲解该模式:

    比如说你把你女朋友给惹毛了,这时候你直接去求原谅可能她不会鸟你。这怎么办?拿出手机,打开美
    团跑腿,叫个外卖小哥给她送点礼物消消气,方便后面的行动。在这个例子中,你自己就是真实角色,外卖小哥就是代理你的角色,由他来代表你去送礼物,这就是代理的意思。

    一、定义抽象主题类

    // 抽象主题类(Subject)类
    // 定义了 实际主题类(RealSubject)和代理类(Proxy)的共用接口
    // 这样就可以在任何使用 RealSubject 的地方使用 Proxy
    class GiveGift {
    public:
        virtual ~GiveGift() = default;
        virtual void GiveDolls() = 0;
        virtual void GiveFlowers() = 0;
        virtual void GiveChocolate() = 0;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    二、定义实际主题类

    // 实际主题(RealSubject)类
    // 定义了代理类(Proxy)真正需要调用的方法
    // final 关键字 表明该类不能做一个基类
    class RealGiveGift final : public GiveGift {
    public:
        void GiveDolls() {
            cout << "give dolls" << endl;
        }
        void GiveFlowers() {
            cout << "give flowers" << endl;
        }
        void GiveChocolate() {
            cout << "give chocolate" << endl;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    三、定义代理类

    // 代理类(Proxy),保存一个引用使的代理对可以访问实体
    // 并提供一个与Subject的相同的接口,这样代理就可以用来替代实体
    class MeiTuanProxy final : public GiveGift {
    public:
        MeiTuanProxy() {
            m_RealObject = new RealGiveGift();
        }
        ~MeiTuanProxy() {
            delete m_RealObject;
            m_RealObject = nullptr;
        }
        void GiveDolls() {
            // do something
            m_RealObject->GiveDolls();
            // do something
        }
        void GiveFlowers() {
            // do something
            m_RealObject->GiveFlowers();
            // do something
        }
        void GiveChocolate() {
            // do something
            m_RealObject->GiveChocolate();
            // do something
        }
    private:
        RealGiveGift *m_RealObject;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    四、客户端

    int main(int argc, char** argv) {
        MeiTuanProxy *meituan = new MeiTuanProxy();
        meituan->GiveDolls();
        meituan->GiveFlowers();
        meituan->GiveChocolate();
        delete meituan;
        meituan = nullptr;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    执行结果

    give dolls
    give flowers
    give chocolate
    
    • 1
    • 2
    • 3

    优点

    1. 可以实现客户类与委托类间的解耦,在不修改委托类代码的情况下能够做一些额外的处理。
    2. 代理模式能将代理对象与真实对象被调用的目标对象分离。
    3. 一定程度上降低了系统的耦合度,扩展性好 。

    缺点

    1. 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
    2. 实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

    适用场合

    从上面的示例和UML图看,先访问代理类再访问真正要访问的对象。似乎这样有点多此一举的味道,其实不然,这是有一定道理的。

    代理类可以在真正的类执行之前,进行一些预处理。比如上面的示例中,外卖小哥看到有订单后,先判断一下要送到哪里,和自己当前位置远不远,要不要绕路等,然后再决定要不要接单。再比如要实现一个代理的服务器去访问真正提供服务的服务器,代理服务器可能要先判断用户是否合法才去访问真正提供服务的服务器,用户访问的其实是代理的接口,只有用户合法才能够去访问真正接口。

  • 相关阅读:
    JC/T 2223-2014 室内装饰装修用木塑型材检测
    09-进程和计划任务管理
    Hadoop MapReduce 文件路径过滤 GlobStatus 与 PathFilter
    Postgresql分区表大量实例与分区建议(LIST / RANGE / HASH / 多级混合分区)
    带你造轮子,自定义一个随意拖拽可吸边的View
    理解DDD设计
    数据结构中树、森林 与 二叉树的转换
    c/c++4个内存分区介绍
    Linux :环境变量
    【Lilishop商城】No2-3.确定软件架构搭建二(本篇包括接口规范、日志处理)
  • 原文地址:https://blog.csdn.net/cfl927096306/article/details/126677048