今天来盘一盘适配器模式。适配器:顾名思义,就是让原本不合适的变为合适的,好似一对男女,没有中间的媒婆是不会互相了解的,好像不太恰当,就这么解释吧,只有有了这个中间人他们才会产生联系,进而相互了解、恋人、深入、结婚,咳咳,没有ghs哦,哈哈哈。
目录
一、适配器模式简介
二、C++适配器代码示例
三、图形编辑器中的适配器模式
四、与模版结合使用
本篇代码:
Thomas_Lbw / Cpp_Design_Patterns · GitCode
一、适配器模式简介
适配器模式是一种设计模式,它允许一个类的接口适配另一个类的接口。适配器模式用于解决两个接口不兼容的问题。适配器将现有的类的接口包装在一个适配器类中,从而让这个现有类具有客户希望的接口。
适配器模式由以下三个组件组成:
- 目标接口:定义客户所需的接口。
- 需要适配的类:定义需要适配的类。
- 适配器类:适配器类实现了目标接口并继承了需要适配的类。
适配器模式常常用于以下场景:
- 当你需要使用一个已有的类,但它的接口不符合您的需求时。
- 当您想创建一个可以重复使用的类,该类可将不兼容的接口转换为客户希望的接口时。
适配器模式的优点:
- 可以让任何两个没有关联的类一起运行。
- 增加了类的透明性和复用性。
- 灵活性和可扩展性都非常好。
适配器模式主要应用在以下情况:
- 让两个不兼容的接口能够正常工作。
- 对一个已存在的类进行包装,使其具有其他接口,以便与其他类一起工作。
- 在不改变现有代码的情况下为一个类增加新的功能。
- 将一个类的接口转换为另一个客户希望的接口,以便使用现有的类。
总结一下,适配器模式是一种很有用的设计模式,特别是在系统集成、复用现有类和代码重构等方面。
二、C++适配器代码示例
假设我们有一个现有的类,该类具有一种特定的接口,但是我们需要使用它时需要它具有不同的接口。我们可以使用适配器模式解决这个问题。
#include <iostream>
#include <string>
// 目标接口
class Target {
public:
virtual void Request() = 0;
};
// 需要适配的类
class Adaptee {
public:
void SpecificRequest() {
std::cout << "SpecificRequest of Adaptee." << std::endl;
}
};
// 适配器类
class Adapter : public Target, private Adaptee {
public:
void Request() {
SpecificRequest();
}
};
int main() {
Target* target = new Adapter();
target->Request();
return 0;
}
适配器类Adapter继承了Target和Adaptee,将两个类中的方法柔和在一起,并且没有更改其代码,像不像媒婆?下面是代码类图:
三、图形编辑器中的适配器模式
开发一个图形编辑器,并且你需要支持多种图形类型,如矩形、圆形和三角形。每种图形类型都具有自己的接口,但你需要统一接口来绘制所有类型的图形。
#include <iostream>
// 目标接口
class Shape {
public:
virtual void Draw() = 0;
};
// 矩形类
class Rectangle {
public:
void DrawRectangle() {
std::cout << "Drawing Rectangle." << std::endl;
}
};
// 圆形类
class Circle {
public:
void DrawCircle() {
std::cout << "Drawing Circle." << std::endl;
}
};
// 三角形类
class Triangle {
public:
void DrawTriangle() {
std::cout << "Drawing Triangle." << std::endl;
}
};
// 矩形适配器
class RectangleAdapter : public Shape, private Rectangle {
public:
void Draw() {
DrawRectangle();
}
};
// 圆形适配器
class CircleAdapter : public Shape, private Circle {
public:
void Draw() {
DrawCircle();
}
};
// 三角形适配器
class TriangleAdapter : public Shape, private Triangle {
public:
void Draw() {
DrawTriangle();
}
};
int main() {
Shape* shapes[3];
shapes[0] = new RectangleAdapter();
shapes[1] = new CircleAdapter();
shapes[2] = new TriangleAdapter();
for (int i = 0; i < 3; i++)
shapes[i]->Draw();
return 0;
}
我们定义了一个Shape
接口,该接口定义了统一的接口来绘制所有图形。然后,我们定义了三个不同的图形类,每个类都有自的接口,但是与目标接口不同。接下来,我们定义了三个适配器类,分别对应矩形、圆形和三角形,每个适配器都继承了Shape
接口,并私有继承了相应的图形类。这样,我们就可以使用适配器对象来访问原本不兼容的图形类,并且在不改变原有代码的情况下实现统一的接口。
类图如下:
四、与模版结合使用
C++ 适配器模式写法一般会使用模板来提高代码的可读性和灵活性。下面是一个简单的例子:
#include <iostream>
// 抽象图形接口
class Shape {
public:
virtual void Draw() = 0;
virtual int GetX() const = 0;
virtual int GetY() const = 0;
virtual ~Shape() = default;
};
// 待适配的矩形类
class Rectangle {
public:
Rectangle(int x, int y) : x_(x), y_(y) {}
void DrawShape() {
std::cout << "Drawing rectangle at (" << x_ << ", " << y_ << ")\n";
}
int GetXCoordinate() const { return x_; }
int GetYCoordinate() const { return y_; }
private:
int x_, y_;
};
// 适配器模板类
template <typename T>
class ShapeAdapter : public Shape {
public:
ShapeAdapter(T* adaptee) : adaptee_(adaptee) {}
void Draw() override {
adaptee_->DrawShape();
}
int GetX() const override {
return adaptee_->GetXCoordinate();
}
int GetY() const override {
return adaptee_->GetYCoordinate();
}
private:
T* adaptee_;
};
int main() {
Rectangle* rectangle = new Rectangle(10, 20);
Shape* shape = new ShapeAdapter<Rectangle>(rectangle);
shape->Draw();
std::cout << "X: " << shape->GetX() << ", Y: " << shape->GetY() << '\n';
delete shape;
delete rectangle;
return 0;
}
这段代码中,我们定义了一个模板类ShapeAdapter
,这个类接受一个类型参数,表示待适配的图形类。适配器类继承了抽象接口Shape
,并实现了其中的三个方法。在实现中,适配器类通过私有成员变量adaptee_
存储待适配的图形对象,并通过继承的接口方法调用相应的图形类方法。
这种写法非常灵活,因为我们可以使用任意的图形类作为适配器的类型参数,并且可以很容易地扩展或替换适配器类的实现。而且,这种写法还易于维护,因为每个图形类的适配器都是独立的,不会影响其他图形类的适配器实现。