本文是设计模式的第三篇-适配器模式(Adapter Pattern)。适配器模式将一个类的接口转换成客户希望的另外一个接口,从而使原本由于接口不兼容而不能一起工作的类可以一起工作。本文提供三个示例来对适配器模式进行详细的阐述。先提供一篇较为简单明了的适配器示例,其次有两个示例来进行深入研究。
文章开头先给大家介绍一下适配器模式的流程图和摘录的几篇适配器模式文章的解释:
- main 开始调用
- Sequence 抽象类
- Queue、Stack栈和队列,继承Sequence
- Deque所有函数的具体实现
我们在应用程序中已经设计好了接口,如果遇到了兼容性问题,为了解决兼容性问题,使用适配器模式提供一个类(第三方库),在不改变原有函数的情况实现一个解决兼容性的类,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
本文作者原创,未经允许请勿转载,本帖原创请勿照抄。
C++ 深入理解适配器模式目录
一、类适配器、对象适配器
从实现层面上划分,适配器模式分为两种:类适配器(多继承方式)、对象适配器(对象组合方式)。
1. 优缺点
优点:可以让任何两个没有关联的类一起运行、提高了类的复用、增加了类的透明度、灵活性好。
缺点:过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
2. 适应场景
- 当想使用一个已存在的类,而它的接口不符合需求时。
- 你想创建一个可复用的类,该类可以与其他不相关的类或不可预见的类协同工作。
- 你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口,对象适配器可以适配它的父接口。
二、示例1
1. cpp源文件
// TestAdapterPattern.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"
#include "Adapter.h"
#include <iostream>
using namespace std;
/*
* 关键代码:适配器继承或依赖已有的对象,实现想要的目标接口。
* 以下示例中,假设我们之前有了一个双端队列,新的需求要求使用栈和队列来完成。
双端队列可以在头尾删减或增加元素。而栈是一种先进后出的数据结构,添加数据时添加到栈的顶部,删除数据时先删 除栈顶部的数据。因此我们完全可以将一个现有的双端队列适配成一个栈。
*/
//双端队列, 被适配类(被调用类)
class Deque
{
public:
void push_back(int x) { cout << "Deque push_back" << endl; }
void push_front(int x) { cout << "Deque push_front" << endl; }
void pop_back() { cout << "Deque pop_back" << endl; }
void pop_front() { cout << "Deque pop_front" << endl; }
};
//顺序类,抽象目标类
class Sequence
{
public:
virtual void push(int x) = 0;
virtual void pop() = 0;
};
//将元素添加到堆栈的顶部。
class Stack : public Sequence
{
public:
//将元素添加到堆栈的顶部。
void push(int x)override
{
deque.push_back(x);
}
//从堆栈中删除顶部元素
void pop()override
{
deque.pop_back();
}
private:
Deque deque;
};
//将元素添加到队列尾部
class Queue : public Sequence
{
public:
//将元素添加到队列尾部
void push(int x)override {
deque.push_back(x);
}
//从队列中删除顶部元素
void pop()override {
deque.pop_front();
}
private:
Deque deque;
};
/*
//栈,后进先出, 适配类
class Stack:public Sequence, private Deque
{
public:
void push(int x)
{
push_front(x);
}
void pop()
{
pop_front();
}
};
//队列,先进先出,适配类
class Queue:public Sequence, private Deque
{
public:
void push(int x)
{
push_back(x);
}
void pop()
{
pop_front();
}
};
*/
int main()
{
Sequence *s1 = new Stack();
Sequence *s2 = new Queue();
s1->push(1); s1->pop();
s2->push(1); s2->pop();
delete s1; delete s2;
/*
//类模式Adapter
Target* pTarget = new Adapter();
pTarget->Request();
//对象模式Adapter1
Adaptee* ade = new Adaptee();
Target* pTarget1 = new Adapter1(ade);
pTarget1->Request();
//对象模式Adapter2
Target* pTarget2 = new Adapter1();
pTarget2->Request();
*/
system("pause");
return 0;
}
2. 运行结果
Deque push_back
Deque pop_back
Deque push_back
Deque pop_front
请按任意键继续. . .
3. 优点
个人认为这个示例很简单的实现了适配器模式的思想,很明了的可以看出解决的过程、方法。
下面我的示例更为全面和详细
三、示例2
出自博客园作者cly C++设计模式-Adapter适配器模式:https://www.cnblogs.com/jiese/p/3166396.html
1. UML
图1:类模式适配器
图2:对象模式适配器
2. Adapter.h
#ifndef _ADAPTER_H_
#define _ADAPTER_H_
//目标接口类,客户需要的接口
class Target
{
public:
Target();
virtual ~Target();
virtual void Request();//定义标准接口
};
//需要适配的类
class Adaptee
{
public:
Adaptee();
~Adaptee();
void SpecificRequest();
};
//类模式,适配器类,通过public继承获得接口继承的效果,通过private继承获得实现继承的效果
class Adapter:public Target,private Adaptee
{
public:
Adapter();
~Adapter();
virtual void Request();//实现Target定义的Request接口
};
//对象模式,适配器类,继承Target类,采用组合的方式实现Adaptee的复用
class Adapter1:public Target
{
public:
Adapter1(Adaptee* adaptee);
Adapter1();
~Adapter1();
virtual void Request();//实现Target定义的Request接口
private:
Adaptee* _adaptee;
};
#endif
3. Adapter.cpp
#include "Adapter.h"
#include <iostream>
using namespace std;
Target::Target()
{}
Target::~Target()
{}
void Target::Request()
{
cout << "Target::Request()" << endl;
}
Adaptee::Adaptee()
{
}
Adaptee::~Adaptee()
{
}
void Adaptee::SpecificRequest()
{
cout << "Adaptee::SpecificRequest()" << endl;
}
//类模式的Adapter
Adapter::Adapter()
{
}
Adapter::~Adapter()
{
}
void Adapter::Request()
{
cout << "Adapter::Request()" << endl;
this->SpecificRequest();
cout << "----------------------------" <<endl;
}
//对象模式的Adapter
Adapter1::Adapter1():_adaptee(new Adaptee)
{
}
Adapter1::Adapter1(Adaptee* _adaptee)
{
this->_adaptee = _adaptee;
}
Adapter1::~Adapter1()
{
}
void Adapter1::Request()
{
cout << "Adapter1::Request()" << endl;
this->_adaptee->SpecificRequest();
cout << "----------------------------" <<endl;
}
4. main.cpp
// TestAdapterPattern.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"
#include "Adapter.h"
#include <iostream>
using namespace std;
//双端队列(被调用函数)
class Deque
{
public:
void push_back(int x) { cout << "Deque push_back" << endl; }
void push_front(int x) { cout << "Deque push_front" << endl; }
void pop_back() { cout << "Deque pop_back" << endl; }
void pop_front() { cout << "Deque pop_front" << endl; }
};
//顺序容器(抽象容器)
class Sequence
{
public:
virtual void push(int x) = 0;
virtual void pop() = 0;
};
//栈和队列分别继承抽象容器,调用不同的函数来进行解决兼容性问题
//栈
class Stack : public Sequence
{
public:
void push(int x) { deque.push_back(x); }
void pop() { deque.pop_back(); }
private:
Deque deque; //双端队列
};
//队列
class Queue : public Sequence
{
public:
void push(int x) { deque.push_back(x); }
void pop() { deque.pop_front(); }
private:
Deque deque; //双端队列
};
int main()
{
/*
Sequence *s1 = new Stack();
Sequence *s2 = new Queue();
s1->push(1); s1->pop();
s2->push(1); s2->pop();
delete s1; delete s2;
*/
//类模式Adapter
Target* pTarget = new Adapter();
pTarget->Request();
//对象模式Adapter1
Adaptee* ade = new Adaptee();
Target* pTarget1 = new Adapter1(ade);
pTarget1->Request();
//对象模式Adapter2
Target* pTarget2 = new Adapter1();
pTarget2->Request();
system("pause");
return 0;
}
本来做这项补充点什么,但是感觉原文章已经很完美的表述了适配器模式。多以不再过多表述。自行执行一遍是最好的理解方法。
在Adapter模式的两种模式中,有一个很重要的概念就是接口继承和实现继承的区别和联系。接口继承和实现继承是面向对象领域的两个重要的概念,接口继承指的是通过继承,子类获得了父类的接口,而实现继承指的是通过继承子类获得了父类的实现(并不统共接口)。在C++中的public继承既是接口继承又是实现继承,因为子类在继承了父类后既可以对外提供父类中的接口操作,又可以获得父类的接口实现。当然我们可以通过一定的方式和技术模拟单独的接口继承和实现继承,例如我们可以通过private继承获得实现继承的效果(private继承后,父类中的接口都变为private,当然只能是实现继承了。),通过纯抽象基类模拟接口继承的效果,但是在C++中pure virtual function也可以提供默认实现,因此这是不纯正的接口继承,但是在Java中我们可以interface来获得真正的接口继承了。
四、示例3
作者:一去丶二三里 C++适配器模式 文章地址:http://blog.csdn.net/liang19890820
五、结尾
设计模式本意并不是让你看代码的实现,100个人表达出来的代码往往有99中不同的写法,受限于业务、流程、想法、目的、代码习惯等等写出来往往都是不同的,而设计模式的核心永远不在于代码的实现、而在于设计思想的体现。
想要深入了解希望大家可以多看同类型的文章、当看过足够多的文章之后总会明白每一个设计模式的写法、用处以及设计思想。
愿你历尽千帆归来,仍是少年。
拥抱2021的开始,挥手告别2020年的最后一刻。
19年写了20多篇博客、20年写了50多篇博客感觉还有很大的提升空间,21年继续努力~
参考文章:https://www.sohu.com/a/123362054_464041 https://developer.aliyun.com/article/119780