在做面向对象的软件开发时我们往往想达到更高的代码可复用性和更合理的软件颗粒度。
根据《设计模式——可复用面向对象软件的基础》所说:“你必须找到相关的对象,以适当的颗粒度将他们回归类,再定义类的接口和继承层次,建立对象之间的基本关系。你的设计应该对手头的问题有针对性,同时对将来的问题和需求也要有足够的通用性。”
内行的设计者知道:不是解决任何问题都要从头做起。他们更愿意复用以前使用的解决方案。这些重复的模式方案解决特定的问题,使得面向对象的设计更灵活、优雅,最终复用性更好。它们帮助设计者将新的设计建立在以往的工作基础上,复用以往的成功设计方案。一个熟悉这些设计模式的设计者不需要再去发现它们,而能够立即将他们应用于设计问题中。
本系列文章主要参考文献为——设计模式,可复用面向对象软件的基础(Design Patterns Elements of Reusable Object
文章目录
摘要
本章主要说明适配器模式,该设计模式主要意图是:将一个类的接口转换成当前需求另一个接口的格式,适配器模式使原本由于接口不兼容无法工作的那些类可以一起工作。
适配器模式做细分有两种:
- 面向类的适配器模式
- 面向对象的适配器模式
本篇文章对上边提到的两种各有一个例子来说明。
面向类的适配器
这里我们举一个面向类的适配器,面向类的适配器通过继承转换调用函数接口的方式进行类的适配,在这个例子中,已存在Deque类(类似双向列表),需要适配的接口Stack类(类似栈),通过一个Adapter类实现使用stack的函数接口,但调用Deque的函数实现。
主要参与者
该设计模式的参与者有4个,分别是:
- Target 定义Client使用的特定接口
- Client 需要适配的
- Adaptee 一个已经存在的接口
- 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个,分别是:
- Target 定义Client使用的特定接口
- Client 需要适配的
- Adaptee 一个已经存在的接口
- 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从前端弹出数据。
补充说明
整篇文章讲了类适配器与对象适配器的实现,那在什么情况下我们可以使用适配器模式呢?
- 在日常开发中可能会遇到工具箱中的一个类所提供的函数接口与我们的需求不同;
- 想创建一个可以复用的类,该类可以与其他不相关的类或未来可能遇到的类协同工作;
- 像对象适配器中所示使用一些已经存在的类,对他们的父类接口进行适配。
如果需要专栏所有设计模式的源代码请留言留下你的联系方式,若能点赞、关注就更棒了!!!
本篇博客中的代码均已通过编译,如有Bug,请提出宝贵意见~