适配器模式定义
适配器是一种结构型设计模式,它能使接口不兼容的对象能够相互合作。
优点
- 客户端通过适配器可以透明地调用目标接口。
- 复用了现存的类,程序员不需要修改原有代码而重用现有的适配者类。
- 将目标类和适配者类解耦,解决了目标类和适配者类接口不一致的问题。
在很多业务场景中符合开闭原则。
缺点
- 适配器编写过程需要结合业务场景全面考虑,可能会增加系统的复杂性。
- 增加代码阅读难度,降低代码可读性,过多使用适配器会使系统代码变得凌乱。
模式的应用场景
- 适配器模式(Adapter)通常适用于以下场景。
- 以前开发的系统存在满足新系统功能需求的类,但其接口同新系统的接口不一致。
使用第三方提供的组件,但组件接口定义和自己要求的接口定义不同。
适配器模式优缺点
适配器模式构成与实现
构成
- 客户端(Client)是包含当前程序业务逻辑的类。
- 客户端接口(Client Interface) 描述了其他类与客户端代码合作时必须遵循的协议。
- 服务(Service)中有一些功能类(通常来自第三方或遗留系统)。客户端与其接口不兼容,因此无法直接调用其功能。
- 适配器(Adapter) 是一个可以同时与客户端和服务交互的类:它在实现客户端接口的同时封装了服务对象。适配器接受客户端通过适配器接口发起的调用,并将其转换为适用于被封装服务对象的调用。
- 客户端代码只需通过接口与适配器交互即可,无需与具体的适配器类耦合。因此,你可以向程序中添加新类型的适配器而无需修改已有代码。这在服务类的接口被更改或替换时很有用:你无需修改客户端代码就可以创建新的适配器类。
实现
ClientInterface.h:
#ifndef CLIENT_INTERFACE_H_
#define CLIENT_INTERFACE_H_
// 圆钉: 客户端接口, 在C++中定义成抽象基类
class RoundPeg {
public:
RoundPeg() {}
virtual int get_radius() = 0;
};
#endif // CLIENT_INTERFACE_H_
Client.h:
#ifndef CLIENT_H_
#define CLIENT_H_
#include "ClientInterface.h"
// 圆孔: 客户端类
class RoundHole {
public:
explicit RoundHole(int r) : radius_(r) {}
int get_radius() {
return radius_;
}
bool isFit(RoundPeg* rp) {
return radius_ >= rp->get_radius();
}
private:
int radius_;
};
#endif // CLIENT_H_
Service.h:
#ifndef SERVICE_H_
#define SERVICE_H_
// 方钉: 适配者类, 即和客户端不兼容的类
class SquarePeg {
public:
explicit SquarePeg(int w) : width_(w) {}
int get_width() {
return width_;
}
private:
int width_;
};
#endif // SERVICE_H_
Adapter.h:
#ifndef ADAPTER_H_
#define ADAPTER_H_
#include <cmath>
#include "Service.h"
#include "ClientInterface.h"
// 方钉适配器: 该适配器能让客户端将方钉放入圆孔中
class SquarePegAdapter : public RoundPeg {
public:
explicit SquarePegAdapter(SquarePeg* sp) : square_peg_(sp) {}
int get_radius() override {
return square_peg_->get_width() * sqrt(2) / 2;
}
private:
SquarePeg* square_peg_;
};
#endif // ADAPTER_H_
main.cpp
#include <iostream>
#include "Client.h"
#include "Adapter.h"
int main() {
system("chcp 65001");
// 半径为10的圆孔
RoundHole* hole = new RoundHole(10);
// 半径分别为5和20的大小方钉 + 它们的适配器
SquarePeg* samll_square_peg = new SquarePeg(5);
SquarePeg* large_square_peg = new SquarePeg(20);
SquarePegAdapter* small_square_peg_adapter = new SquarePegAdapter(samll_square_peg);
SquarePegAdapter* large_square_peg_adapter = new SquarePegAdapter(large_square_peg);
if (hole->isFit(small_square_peg_adapter)) {
std::cout << "small square peg fits the hole" << std::endl;
} else {
std::cout << "small square peg don't fit the hole" << std::endl;
}
if (hole->isFit(large_square_peg_adapter)) {
std::cout << "large square peg fits the hole" << std::endl;
} else {
std::cout << "large square peg don't fit the hole" << std::endl;
}
system("pause");
}