• C++设计模式之适配器模式(结构型模式)


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

    什么是适配器模式

    将一个类的接口变换成客户端所期待的另一种接口, 从而使得原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

    它包括类适配器对象适配器,本文针对的是对象适配器。适配器模式让我们在设计时不必再关心现存类接口问题。

    在这里插入图片描述

    UML类图

    在这里插入图片描述

    适配器模式中的角色:

    1. 目标(Target):定义一个客户端使用的特定接口。
    2. 客户端(Client):使用目标接口,与和目标接口一致的对象合作。
    3. 被适配者(Adaptee):一个现存需要适配的接口。
    4. 适配器(Adapter):负责将Adaptee的接口转换为Target的接口。适配器是一个具体的类,这是该模式的核心。

    Version 1.0

    下面我们使用手机充电来讲解该模式:

    手机充电需要电源适配器将220V的交流电转化为手机锂电池需要的5V直流电。

    一、定义目标类

    DC5类:目标类(Target)

    class DC5 {
    public:
        virtual int output5V() = 0;
    };
    
    • 1
    • 2
    • 3
    • 4

    二、定义被适配者

    AC220类:被适配的类(Adaptee)

    class AC220 {
    public:
        int output220V() {
            int output = 220;
            cout << "Current is AC" << output << "V" << endl;
            return output;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    三、定义适配器

    AdapterDC5类:适配器类(Adapter)

    class AdapterDC5 : public DC5 {
    public:
        AdapterDC5(AC220 *ac220) : m_ac220(ac220) {}
        int output5V() {
            int output = m_ac220->output220V() / 44;
            cout << "Adapte succeed, current is DC" << output << "V" << endl;
            return output;
        }
    private:
        /* have a adaptee */
        AC220 *m_ac220;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    四、客户端

    class Mobile
    {
    public:
        Mobile(DC5 *dc5) : m_dc5(dc5) {}
        void charging() {
            int output = m_dc5->output5V();
            if(output == 5)
                cout << "Changing" << endl;
            else if(output > 5)
                cout << "Bomb" << endl;
        }
    private:
        DC5 *m_dc5;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    main函数

    int main(int argc, char** argv) {
        AC220 *pAC220 = new AC220;
        Mobile *pIphone = new Mobile(new AdapterDC5(pAC220));
        pIphone->charging();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    执行结果

    Current is AC220V
    Adapte succeed, current is DC5V
    Changing
    
    • 1
    • 2
    • 3

    STL

    在 STL 中就用到了适配器模式。STL 实现了一种数据结构,称为双端队列(deque),
    支持前后两端的插入与删除。STL 实现栈和队列时,没有从头开始定义它们,而是直接
    使用双端队列实现的。这里双端队列就扮演了适配器的角色。队列用到了它的后端插入,
    前端删除;而栈用到了它的后端插入,后端删除。

    class MyDeque {
    public:
        void push_back() {}
        void push_front() {}
        void pop_back() {}
        void pop_front() {}
    };
    
    class MyStack {
    public:
        void push() {
            md.push_back();
        }
        void pop() {
            md.pop_back();
        }
    private:
        MyDeque md;
    };
    
    class MyQueue {
    public:
        void enQueue() {
            md.push_back();
        }
        void deQueue() {
            md.pop_front();
        }
    private:
        MyDeque md;
    };
    
    • 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
    • 30
    • 31

    优点

    1. 将目标类和适配器类解耦。
    2. 增加了类的透明性和复用性,将具体的实现封装在适配器类中,对于客户端类来说是透明的,而且
      提高了适配器的复用性。
    3. 灵活性和扩展性都非常好,符合开闭原则。

    缺点

    1. 一次最多只能适配一个适配器类,不能同时适配多个适配器。
    2. 适配器类不能为最终类。
    3. 目标抽象类只能为接口,不能为类,其使用有一定的局限性。

    适用场合

    类适配器与对象适配器的使用场景一致,仅仅是实现手段稍有区别,二者主要用于如下场景:

    1. 想要使用一个已经存在的类,但是它却不符合现有的接口规范,导致无法直接去访问,这时创建一个适配器就能间接去访问这个类中的方法。
    2. 我们有一个类,想将其设计为可重用的类(可被多处访问),我们可以创建适配器来将这个类来适配其他没有提供合适接口的类。

    以上两个场景其实就是从两个角度来描述一类问题,那就是要访问的方法不在合适的接口里,一个从接口出发(被访问),一个从访问出发(主动访问)。

  • 相关阅读:
    Mapbox-gl 关闭所有Popup,以及关闭按钮出现黑色边框bug
    【回溯算法】leetcode 784. 字母大小写全排列
    数据结构:阶段测试(查漏补缺)
    学习java第一百一十三天
    北京大学肖臻老师《区块链技术与应用》公开课笔记:以太坊原理(二):GHOST、挖矿算法、难度调整、权益证明
    Spring中的事务
    农产品经营小程序商城的作用是什么?
    golang--module
    一种通用的业务监控触发方案设计
    如何配置Header Editor
  • 原文地址:https://blog.csdn.net/cfl927096306/article/details/126676976