结构型模式
适配器模式
模式定义
适配器模式(Adapter Pattern):将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。
模式结构
适配器模式包含以下角色:
- Target:目标抽象类
- Adapter:适配器类
- Adaptee:适配者类
- Client:客户类
适配器模式可分为对象适配器和类适配器。
示例代码
#include <iostream>
#include <memory>
class Target {
public:
Target() = default;
virtual ~Target() = default;
virtual void request() = 0;
};
class Adaptee {
public:
Adaptee() = default;
~Adaptee() = default;
void specific_request() {
std::cout << "specific request" << std::endl;
}
};
using AdapteePtr = std::shared_ptr<Adaptee>;
class ObjectAdapter : public Target {
public:
explicit ObjectAdapter(AdapteePtr adaptee) : adaptee_(std::move(adaptee)) {
}
~ObjectAdapter() override = default;
void request() override {
adaptee_->specific_request();
}
private:
AdapteePtr adaptee_;
};
class ClassAdapter : public Target, private Adaptee {
public:
ClassAdapter() = default;
~ClassAdapter() override = default;
void request() override {
specific_request();
}
};
int main() {
ClassAdapter class_adapter;
class_adapter.request();
ObjectAdapter object_adapter(std::make_shared<Adaptee>());
object_adapter.request();
}
优点
- 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
- 增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性。
- 灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。
类适配器模式还有以下优点:
- 由于适配器类是适配者类的子类,因此可以在适配器类中置换一些适配者的方法,使得适配器的灵活性更强。
对象适配器还有以下有带你:
- 一个对象适配器可以把多个不同的适配者适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口。
缺点
类适配器的缺点:
- 对于不支持多重继承的语言,一次最多只能适配一个适配者类,而且目标抽象类只能为抽象类,不能为具体类,其使用有一定的局限性,不能将一个适配者类和它的子类都适配到目标接口。
对象适配器的缺点:
- 与类适配器模式相比,要想置换适配者类的方法就不容易。如果一定要置换掉适配者类的一个或多个方法,就只好先做一个适配者类的子类,将适配者类的方法置换掉,然后再把适配者类的子类当做真正的适配者进行适配,实现过程较为复杂。
适用场景
- 系统需要使用现有的类,而这些类的接口不符合系统的需要。
- 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
桥接模式
模式定义
桥接模式(Bridge Pattern):针对系统中有两个独立变化维度的类,将抽象部分与它的实现部分分离,使它们都可以独立地变化。又称为柄体(Handle and Body)模式或接口(Interface)模式。
模式结构
桥接模式包含以下角色:
- Abstraction:抽象类
- RefinedAbstraction:扩充抽象类
- Implementor:实现类接口
- ConcreteImplementor:具体实现类
示例代码
示例代码对应的结构图如下:
#include <iostream>
#include <memory>
/* Implementor */
class Skin {
public:
Skin() = default;
virtual ~Skin() = default;
virtual void show() = 0;
};
using SkinPtr = std::shared_ptr<Skin>;
/* ConcreteImplementor */
class CuteSkin : public Skin {
public:
CuteSkin() = default;
~CuteSkin() override = default;
void show() override {
std::cout << "skin: cute skin" << std::endl;
}
};
/* ConcreteImplementor */
class CoolSkin : public Skin {
public:
CoolSkin() = default;
~CoolSkin() override = default;
void