结构型模式
这些模式关注对象之间的组合和关系,旨在解决如何构建灵活且可复用的类和对象结构。它主要有:
- 适配器模式(Adapter Pattern)
- 桥接模式(Bridge Pattern)
- 过滤器模式(Filter、Criteria Pattern)
- 组合模式(Composite Pattern)
- 装饰器模式(Decorator Pattern)
- 外观模式(Facade Pattern)
- 享元模式(Flyweight Pattern)
- 代理模式(Proxy Pattern)
我们详细来看一看适配器模式。
适配器模式
适配器模式是一种结构型设计模式,它能使接口不兼容的对象能够相互合作。“适配器模式”将一个类的接口转换成客户希望的另外一个接口,使得原本不兼容的接口一起工作。
意义
在于将某些功能与第三方需求接口适配对接,且避免第三方接口与功能代码过多耦合。
在设计初初,不要考虑使用此模式。仅在功能完善,需要实现第三方接口时,没必要迎合第三方的需求对原来的设计大动刀戈,可以尝试使用适配器模式。
多用于想应用某些功能,但是功能类的接口与需求的接口不兼容时,采用适配器模式来解决。主要应用在以下场景:
- 新旧接口兼容软件版本升级,部分旧接口还在被使用。需要保留旧的接口,增加新接口,使两者兼容。
- 第三方接口的适配在系统功能稳定的情况下,有第三方新的接口需求需要对接。
- 统一多个类相同功能的接口例如统一不同类型数据库的访问接口。
比如我们实现TypeC接口手机联通USB接口的U盘。手机可插入的接口为TypeC或其他非USB接口,但U盘为USB接口,与需求接口不符。因此,可通过适配器完成USB与TypeC的对接。
适配器模式有两种实现方法,类适配器和对象适配器。
类适配器
以多继承的方式实现。
- Target: 客户端期望接口类
- Adaptee: 实际需要的功能类
- Adapter: 将接口类与功能类衔接的适配器类
- Client: 客户端代码
class CUsbDisk
{
public:
virtual ~CUsbDisk()
{}
virtual void ConnectDevice()
{
std::cout << "Connect usb port!" << std::endl;
}
};
class TypeCInterface
{
public:
virtual ~TypeCInterface()
{}
void ConnectDevice()
{
std::cout << "Connect Type-C port!" << std::endl;
}
};
class Adapter : public CUsbDisk, public TypeCInterface
{
public:
void ConnectDevice()
{
TypeCInterface::ConnectDevice();
}
};
int main(int argc, char *argv[])
{
CUsbDisk *theDisk = new Adapter();
theDisk->ConnectDevice();
delete theDisk;
return 0;
}
对象适配器
在适配器类中,包装适配者的接口。
- Target: 客户端期望接口类
- Adaptee: 实际需要的功能类
- Adapter: 将接口类与功能类衔接的适配器类
- Client: 客户端代码
从类图上可以看出两者的差异,类适配器采用多继承方式,对象适配器采用对适配者Adaptee接口方式。两种方式都能完成Target接口与Adaptee接口对接。
class CUsbDisk
{
public:
virtual ~CUsbDisk() {}
virtual void ConnectDevice()
{
cout << "Connect usb port." << endl;
}
};
class CTypeCInterface
{
public:
virtual ~CTypeCInterface() {}
void ConnectDevice()
{
cout << "Connect Type-C port." << endl;
}
};
class CAdapter : public CUsbDisk
{
public:
CAdapter()
{
mpAdaptee = new CTypeCInterface();
}
~CAdapter()
{
if (NULL != mpAdaptee) {
delete mpAdaptee;
}
}
void ConnectDevice()
{
if (NULL != mpAdaptee) {
mpAdaptee->ConnectDevice();
} else {
cout << "Adapter abnormal. Connect fail!" << endl;
}
}
private:
CTypeCInterface *mpAdaptee;
};
int main(int argc, char *argv[])
{
CUsbDisk *theDisk = new CAdapter();
theDisk->ConnectDevice();
delete theDisk;
return 0;
}
总结
- 适配器模式主要原理: 在于实现客户接口时,关联上已存在的功能接口。一种使用过多继承方式,一种通过类之间依赖的方式,都能实现。
- 为统一多个功能相同的类接口时,类适配器模式是更适合的。比较典型的例子如,MySql和SQLServer等多种类型数据库的访问接口的统一。
- C++编程不要轻易使用多继承!
- 另外,文中也有说过。在软件开发初,无第三方需求接口的情况下,不要考虑此模式的使用。往往适配器模式的使用,会让代码看起来像一个补丁,修修补补。
- 「适配器模式」看起来与「外观模式」相似,都是与外部对接。其实有很大不同: 「外观模式」是定义一套新的接口,而「适配器模式」则是运用已有的接口。「外观模式」是在已有复杂的接口上,再封一层简单的接口,方便客户端使用。「适配器模式」则是结合已有的功能,实现或重载已经存在的客户端接口。