在软件工程中,设计模式(Design Pattern)是对软件设计普遍存在(反复出现)的各种问题,锁提出的解决防范。根据模式的目的来划分的话,GoF(Gang of Four) 设计模式可以分为以下三种类型:
1.创建型模式:用来描述“如何创建对象”,它的主要特点是“将对象的创建和使用分离”。包括单例、原型、工厂方法、抽象工厂和建造者5种模式。
2.结构型模式:用来描述如何将类或对象按照某种布局组成更大的结构。包括代理、适配器、侨接、装饰、外观、享元和组合7种模式。
3.行为型模式:用来识别对象之间的常用交流模式以及如何分配职责。包括模版方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录和解释器11种模式。
今天介绍1种常用的设计模式。
适配器模式(Adapter)
在实际生活中,也存在适配器的使用场景,比如:港式插头转换器、电源适配器和USB转接口。而在软件工程中,适配器模式的作用是解决两个软件实体间的接口不兼容的问题。使用适配器模式之后,原本由于接口不兼容的两个软件实体就可以一起工作。工程中,通俗的讲就是我们已经有了一些类,而这些类不能满足新的需求,此时就可以考虑是否能将现有的类适配成可以满足新需求的类。适配器类需要继承或依赖已有的类,实现想要的目标接口。
缺点:过多地使用适配器,会让系统非常凌乱,不易整体进行把握。比如,明明看到调用的是A接口,其实内部适配成了B接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
使用复合实现适配器模式
/*
关键代码:适配器继承或依赖已有的对象,实现想要的目标接口。
以下示例中,假设我们之前有了一个双端队列,新的需求要使用栈和队列来完成。
双端队列可以在头尾删减或增加元素。而栈是一种先进后出的数据结构,添加数据时添加到栈的顶部,删除数据时先删顶部的数据。因此我们完全可以将一个现有的双端队列适配成一个栈。
*/
//双端队列, 被适配类
class Deque {
public:
void push_back(int x) {
cout << "Deque push_back:" << x << endl;
}
void push_front(int x) {
cout << "Deque push_front:" << x << 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 {
m_deque.push_front(x);
}
//从堆栈中删除顶部元素
void pop() override {
m_deque.pop_front();
}
private:
Deque m_deque;
};
//队列,先进先出,适配类
class Queue:public Sequence {
public:
// 将元素添加到队列尾部
void push(int x) override {
m_deque.push_back(x);
}
// 从队列中删除顶部元素
void pop() override {
m_deque.pop_front();
}
private:
Deque m_deque;
}
使用继承实现适配器模式
// 双端队列,被适配类
class Deque {
public:
void push_back(int x) {
cout << "Deque push_back:"<< x << endl;
}
void push_front(int x) {
cout <<"Deque push_front:"<< x << 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, 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();
}
};
应用场景:
以前开发的系统存在满足新系统功能需求的类,但其接口同新系统的接口不一致。
使用第三方提供的组件,但组件接口定义和自己要求的接口定义不同。