适配器模式(adapter)

发布时间 2023-09-07 18:06:39作者: 下夕阳

适配器模式

1 作用

名字很形象的说出了模式的作用:当有一个需求需要Target的接口,然后有一个现成的Adaptee接口,为了让Adaptee接口匹配上Target接口,就需要使用Adapter,在Adapter中将Adaptee适配Target。

Adapter和Bridge模式都使用了关联关系,Bridge中关联的两个类都可以扩展,Adapter中只会扩展Target产生新的Adapter,Adatee是固定不修改了。

2 实现方式

实现Adapter适配器设计模式有两种方式:组合(compositon, has-a关系)和继承(inheritance,is-a关系)。

对象适配器模式使用组合,UML图如下:

img

就是Aapter里实际上包含一个被适配的对象。(组合)又继承了target。因此如果要用到target的方法,直接调用父类的方法,如果要用到被适配者的方法, 就调用内部成员的函数。

3 C++代码

STL里的stack和queue都是adapter,底层是deque,隐藏了deque的一些接口,使得其可以达到FIFO是queue,LIFO是stack。

下面用适配器模式模拟将deque生成queue和stack接口。

img

SequentialContainer.h

#include <deque>

#ifndef __QUEUE__H__
#define __QUEUE__H__


template<typename T>
class SequentialContainer {
    public:
        SequentialContainer() = default;
        virtual ~SequentialContainer() {} // 虚析构函数
        virtual void put(const T &v) = 0;
        virtual T pop() = 0;
};

template<typename T>
class Stack:public SequentialContainer<T> {
    public:
        Stack(std::deque<T> *dq):dq(dq){}
        ~Stack() { delete dq; } // 析构指针对象指向的空间
        void put(const T &v) override { dq->emplace_front(v);}
        T pop() override {
            if(dq->size()>0){
                int tmp =  dq->front();
                dq->pop_front();
                return tmp;
            } else {
                return 0;
            }
        }
    private:
        std::deque<T> *dq;
};


template<typename T>
class Queue:public SequentialContainer<T> {
    public:
        Queue(std::deque<T> *dq):dq(dq){}
        ~Queue() { delete dq; } // 析构指针对象指向的空间
        void put(const T &v) override { dq->emplace_front(v);}
        T pop() override {
            int tmp =  dq->back();
            dq->pop_back();
            return tmp;
        }
    private:
        std::deque<T> *dq;
};

#endif

test.h

#include <iosteam>
#include <deque>
#include "SequntialContainer.h"

using namespace std;

int main() {    
    SequentialContainer<int> *stack = new Stack<int>(new deque<int>);
    SequentialContainer<int> *queue  = new Queue<int>(new deque<int>);

    for(int i=0; i<10; ++i){
        stack->put(i);
        queue->put(i);
    }

    cout<<"stack output:";
    for(int i=0; i<11; ++i)
        cout<<stack->pop()<<" ";
    cout<<endl;

    cout<<"fifo output:";
    for(int i=0; i<11; ++i)
        cout<<queue->pop()<<" ";
    cout<<endl;

    delete stack; // 析构动态生成的对象
    delete queue;
  return 0; 
}

输出:

超出队列或者stack的长度后,输出都是0.

Adpter中不保存Adaptee的指针,而是对象,这样就不要析构函数了。

SequentialContainer.h

#include <deque>

#ifndef __QUEUE__H__
#define __QUEUE__H__


template<typename T>
class SequentialContainer {
    public:
        SequentialContainer() = default;
        virtual ~SequentialContainer(){} // 虚析构函数
        virtual void put(const T &v) = 0;
        virtual T pop() = 0;
};

template<typename T>
class Stack:public SequentialContainer<T> {
    public:
        Stack(std::deque<T> dq):dq(dq){}
        void put(const T &v) override { dq.emplace_front(v);}
        T pop() override {
            if(dq.size()>0){
                int tmp =  dq.front();
                dq.pop_front();
                return tmp;
            } else {
                return 0;
            }
        }
    private:
        std::deque<T> dq;
};


template<typename T>
class Queue:public SequentialContainer<T> {
    public:
        Queue(std::deque<T> dq):dq(dq){}
        void put(const T &v) override { dq.emplace_front(v);}
        T pop() override {
            int tmp =  dq.back();
            dq.pop_back();
            return tmp;
        }
    private:
        std::deque<T> dq;
};

#endif

test.cc

#include <iostream>
#include "SequentialContainer.h"

using namespace std;

int main() {    
    SequentialContainer<int> *stack = new Stack<int>(deque<int>());
    SequentialContainer<int> *queue  = new Queue<int>(deque<int>());

    for(int i=0; i<10; ++i){
        stack->put(i);
        queue->put(i);
    }

    cout<<"stack output:";
    for(int i=0; i<11; ++i)
        cout<<stack->pop()<<" ";
    cout<<endl;

    cout<<"queue output:";
    for(int i=0; i<11; ++i)
        cout<<queue->pop()<<" ";
    cout<<endl;

    delete stack; // 析构动态生成的对象
    delete queue;

    return 0;
}