简单易懂23种设计模式——适配器模式【含C++代码实例】

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

摘要

  本章主要说明适配器模式,该设计模式主要意图是:将一个类的接口转换成当前需求另一个接口的格式,适配器模式使原本由于接口不兼容无法工作的那些类可以一起工作。
  适配器模式做细分有两种:

  1. 面向类的适配器模式
  2. 面向对象的适配器模式

本篇文章对上边提到的两种各有一个例子来说明。

面向类的适配器

这里我们举一个面向类的适配器,面向类的适配器通过继承转换调用函数接口的方式进行类的适配,在这个例子中,已存在Deque类(类似双向列表),需要适配的接口Stack类(类似栈),通过一个Adapter类实现使用stack的函数接口,但调用Deque的函数实现。

主要参与者

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

  1. Target 定义Client使用的特定接口
  2. Client 需要适配的
  3. Adaptee 一个已经存在的接口
  4. Adapter 对Adaptee与Target接口进行适配的适配器 deque

具体实现代码

   接下来我们通过一个实例代码来说明具体实现:

现有接口(Adaptee )

/****************************************************************
 Author :   BingLee 
 Date   :   2019-07-16
 Info   :   
 https://blog.csdn.net/Bing_Lee (C)All rights reserved.
******************************************************************/
#ifndef DEQUE_H
#define DEQUE_H
#include <vector>
#include <stdio.h>
//Adaptee 已经存在的接口
class Deque
{
public:
    Deque(){}
    void pop_back()
    {
        if(m_dnum.size()<=0)
        {
            return;
        }
        else
        {
            m_dnum.erase(m_dnum.end() -1);
            printf("this is class Deque popback\n");
        }
    }
    void pop_front()
    {
        if(m_dnum.size()<=0)
        {
            return;
        }
        else
        {
            m_dnum.erase(m_dnum.begin());
            printf("this is class Deque popfront\n");
        }
    }
    void push_back(int num)
    {
        m_dnum.push_back(num);
        printf("this is class Deque pushback\n");
    }
    void push_front(int num)
    {
        m_dnum.insert(m_dnum.begin(), num);
        printf("this is class Deque pushfront\n");
    }
private:
    std::vector<int> m_dnum;
};
#endif // DEQUE_H

对接接口(Target )

/****************************************************************
 Author :   BingLee 
 Date   :   2019-07-16
 Info   :   
 https://blog.csdn.net/Bing_Lee (C)All rights reserved.
******************************************************************/
#ifndef STACK_H
#define STACK_H
#include <vector>
//Target 对接接口
class Stack
{
public:
    Stack(){}
    virtual void pop()
    {
        if(m_num.size()<=0)
            return;
        else
            m_num.erase(m_num.end());
    }
    virtual void push(int num)
    {
        m_num.push_back(num);
    }
private:
    std::vector<int> m_num;
};
#endif // STACK_H

类适配器(Adapter )

/****************************************************************
 Author :   BingLee 
 Date   :   2019-07-16
 Info   :   
 https://blog.csdn.net/Bing_Lee (C)All rights reserved.
******************************************************************/
#ifndef ADAPTER_H
#define ADAPTER_H
#include "Deque.h"
#include "Stack.h"
//Adapter 适配器
class Adapter :public Deque, public Stack
{
public:
    Adapter(){}
    void push(int num)
    {
        this->push_back(num);
    }
    void pop()
    {
        this->pop_back();
    }
};
#endif // ADAPTER_H

用户使用(Client)

/****************************************************************
 Author :   BingLee 
 Date   :   2019-07-16
 Info   :   
 https://blog.csdn.net/Bing_Lee (C)All rights reserved.
******************************************************************/
#include "Adapter.h"
// Client 需要适配的
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    Stack *s = new Adapter();
    s->push(0);
    s->push(1);
    s->pop();
    s->pop();
    return a.exec();
}

输出结果

在这里插入图片描述

面向对象的适配器

这里我们举一个面向对象的适配器,面向对象的适配器通过包含适配器对象直接进行适配,在这个例子中,已存在Deque类(Adapter 类似双向列表),特定接口Suquence( Adaptee),继承接口并包含Deque对象的Target类。
Stack和Queue通过操作Deque来实现接口适配。

主要参与者

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

  1. Target 定义Client使用的特定接口
  2. Client 需要适配的
  3. Adaptee 一个已经存在的接口
  4. Adapter 对Adaptee与Target接口进行适配的适配器 deque

具体实现代码

   接下来我们通过一个实例代码来说明具体实现:

类适配器(Adapter )

/****************************************************************
 Author :   BingLee 
 Date   :   2019-07-16
 Info   :   
 https://blog.csdn.net/Bing_Lee (C)All rights reserved.
******************************************************************/
#ifndef DEQUE_H
#define DEQUE_H
#include <vector>
#include <stdio.h>

class Deque
{
public:
    Deque(){}
    void pop_back()
    {
        if(m_dnum.size()<=0)
        {
            return;
        }
        else
        {
            printf(" class Deque popback %d\n", m_dnum.back());
            m_dnum.erase(m_dnum.end() -1);
        }
    }
    void pop_front()
    {
        if(m_dnum.size()<=0)
        {
            return;
        }
        else
        {
            printf(" class Deque popfront %d\n", m_dnum.front());
            m_dnum.erase(m_dnum.begin());
        }
    }
    void push_back(int num)
    {
        printf(" class Deque pushback %d\n", num);
        m_dnum.push_back(num);
    }
    void push_front(int num)
    {
        m_dnum.insert(m_dnum.begin(), num);
        printf(" class Deque pushfront %d\n", num);
    }
private:
    std::vector<int> m_dnum;
};
#endif // DEQUE_H

现有接口(Adaptee )

/****************************************************************
 Author :   BingLee 
 Date   :   2019-07-16
 Info   :   
 https://blog.csdn.net/Bing_Lee (C)All rights reserved.
******************************************************************/
#ifndef SEQUENCE_H
#define SEQUENCE_H

class Sequence
{
public:
    Sequence(){}
    virtual void push(int num) = 0;
    virtual void pop() = 0;
};
#endif // SEQUENCE_H

对接接口(Target )

/****************************************************************
 Author :   BingLee 
 Date   :   2019-07-16
 Info   :   
 https://blog.csdn.net/Bing_Lee (C)All rights reserved.
******************************************************************/
#ifndef QUEUE_H
#define QUEUE_H
#include "Deque.h"
#include "Sequence.h"
class Queue : public Sequence
{
public:
    Queue(){m_num = new Deque;}
    void pop()
    {
        printf("class Queue,");
        m_num->pop_front();
    }
    void push(int num)
    {
        printf("class Queue,");
        m_num->push_back(num);
    }
private:
    Deque *m_num;
};
#endif // QUEUE_H
/****************************************************************
 Author :   BingLee 
 Date   :   2019-07-16
 Info   :   
 https://blog.csdn.net/Bing_Lee (C)All rights reserved.
******************************************************************/
#ifndef STACK_H
#define STACK_H

#include "Sequence.h"
#include "Deque.h"

class Stack : public Sequence
{
public:
    Stack(){m_num = new Deque;}
    void pop()
    {
        printf("class Stack,");
        m_num->pop_back();
    }
    void push(int num)
    {
        printf("class Stack,");
        m_num->push_back(num);
    }
private:
    Deque *m_num;
};
#endif // STACK_H

用户使用(Client)

#include <QCoreApplication>
#include "Stack.h"
#include "Queue.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    Sequence *stack = new Stack();
    Sequence *queue = new Queue();
    stack->push(0);
    stack->push(1);
    queue->push(0);
    queue->push(1);
    stack->pop();	//stack pop from back of vector
    queue->pop();	//queue pop from front of vector
    delete stack,queue;
    return a.exec();
}

输出结果

在这里插入图片描述
这里可以发现,stack调用pop从末端弹出数据,queue调用pop从前端弹出数据。

补充说明

整篇文章讲了类适配器与对象适配器的实现,那在什么情况下我们可以使用适配器模式呢?

  1. 在日常开发中可能会遇到工具箱中的一个类所提供的函数接口与我们的需求不同;
  2. 想创建一个可以复用的类,该类可以与其他不相关的类或未来可能遇到的类协同工作;
  3. 像对象适配器中所示使用一些已经存在的类,对他们的父类接口进行适配。

如果需要专栏所有设计模式的源代码请留言留下你的联系方式,若能点赞、关注就更棒了!!!
本篇博客中的代码均已通过编译,如有Bug,请提出宝贵意见~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

机器人梦想家

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值