23種設計模式C++實現——適配器模式

   在做面向對象的軟件開發時我們往往想達到更高的代碼可複用性和更合理的軟件顆粒度。
  根據《設計模式——可複用面向對象軟件的基礎》所說:“你必須找到相關的對象,以適當的顆粒度將他們迴歸類,再定義類的接口和繼承層次,建立對象之間的基本關係。你的設計應該對手頭的問題有針對性,同時對將來的問題和需求也要有足夠的通用性。
  內行的設計者知道:不是解決任何問題都要從頭做起。他們更願意複用以前使用的解決方案。這些重複的模式方案解決特定的問題,使得面向對象的設計更靈活、優雅,最終複用性更好。它們幫助設計者將新的設計建立在以往的工作基礎上,複用以往的成功設計方案。一個熟悉這些設計模式的設計者不需要再去發現它們,而能夠立即將他們應用於設計問題中。
  本系列文章主要參考文獻爲——設計模式,可複用面向對象軟件的基礎(Design Patterns Elements of Reusable Object-Oriented SoftWare Erich.),內部代碼基本用C++語言編寫。
    彙總鏈接:23種設計模式C++實現——概要(索引彙總)

摘要

  本章主要說明適配器模式,該設計模式主要意圖是:將一個類的接口轉換成當前需求另一個接口的格式,適配器模式使原本由於接口不兼容無法工作的那些類可以一起工作。
  適配器模式做細分有兩種:

  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,請提出寶貴意見~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章