往期回顾:
3. 用C语言实现原型模式!
注:若没有看过往期的小伙伴,请先按顺序阅读,对C语言实现设计模式方法有一定的了解。
一、简介
1. Adapter模式: 也叫适配器模式,是构造型模式之一,通过 Adapter模式可以改变已有类(或外部类)的接口形式。
2. 适用于:是将一个类的接口转换成客户希望的另外一个接口。使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
3. 优点: 提高代码的复用度、灵活性高
4. UML类图:
目标角色(Target):客户端期望的接口,抽象类或接口
适配者角色(Adaptee):已存在接口,但是和客户端期望的接口不一致
适配器角色(Adaper):适配器,将适配者角色现有的接口进行适配,满足目标角色
二、设计思路
适配器这个概念,我们在生活中是很常见的,比如电源适配器,将市电220V转换为设备所需要的电压;电源三脚插头通过转换变成两脚插头使用等这些都存在适配器的概念。本篇以手机想使用USB接口的U盘为例,手机直接使用不了USB接口的设备,需要将USB接口转换为Type-C的接口,才可以使用。
目标TARGET: 最终客户期望的接口,本例即期望Type-C接口
//目标target,即现在业务需要的对象接口
typedef struct TypeCDisk
{
void (*use_typeC_disk)(void* obj, int len); //使用TYPE-C接口
void (*free)(void* obj);//释放资源
}TypeCDisk;
适配者角色Adaptee:已存在老的接口,本例即USB接口的U盘
//已经存在的老业务模块
typedef struct USBDisk
{
//使用USB接口的U盘
void (*use_usb_disk)(void* obj, char *color, char *texture, int len);
void (*free)(void *obj);//释放资源
char color[32]; //U盘颜色
char texture[32]; //U盘材质
int wire_len; //U盘线长
}USBDisk;
//使用USB接口U盘
static void use_usb_disk(void* obj, char *color, char *texture, int len)
{
if(!obj || !color || !texture) return;
USBDisk* usb = (USBDisk*)obj;
sprintf(usb->color, "%s", color);
sprintf(usb->texture, "%s", texture);
usb->wire_len = len;
printf("材质:%s 颜色:%s 长度:%dCM USB接口U盘\n",usb->texture,usb->color,usb->wire_len);
}
//释放资源
static void free_usb_disk(void *obj)
{
if(obj) free(obj);
obj=NULL;
}
//USB接口U盘构造函数,创建一个USBDisk对象
USBDisk* constructor_usb_disk(void)
{
USBDisk* usb = (USBDisk*)malloc(sizeof(USBDisk));
usb->use_usb_disk = use_usb_disk;
usb->free = free_usb_disk;
return usb;
}
适配器角色(Adaper):适配器即转换器,将USB接口转换为Type-C接口的东西
//适配器结构,继承目标target,关联适配者角色Adaptee(即存在老的模块)
typedef struct AdapterDisk
{
void (*use_typeC_disk)(void* obj, int len); //使用Type-C接口的U盘
void (*free)(void* obj); //释放资源
int wire_len;
USBDisk* usb;
}AdapterDisk;
//适配器使用Type-C接口U盘
static void adapter_use_typeC_disk(void* obj, int len)
{
AdapterDisk* disk = (AdapterDisk*)obj;
disk->wire_len = len;
//将USB接口与Type-C接口进行适配
disk->usb->use_usb_disk(disk->usb,"黑色","铝制",len);
}
//释放资源
static void adapter_use_typeC_free(void* obj)
{
if(obj) free(obj);
obj=NULL;
}
//适配器构造带参函数,需要传入适配者角色Adaptee(即存在老的模块)对象
//返回一个适配器对象
AdapterDisk* constructor_adapter_disk(USBDisk* usbdisk)
{
AdapterDisk* disk = (AdapterDisk*)malloc(sizeof(AdapterDisk));
disk->use_typeC_disk = adapter_use_typeC_disk;
disk->free = adapter_use_typeC_free;
disk->usb = usbdisk;
return disk;
}
三、测试验证
先创建一个适配者角色Adaptee(即存在老的模块)对象,将Adaptee作为参数传入适配器构造函数,创建适配器对象,此时转换提供了Type-C接口,手机便可以使用Type-C接口的U盘。
int main(void)
{
TypeCDisk* typeC=NULL;
printf("1.创建一个USB接口U盘。\n");
USBDisk* usb = constructor_usb_disk();
printf("2.连接适配器。\n");
typeC = (TypeCDisk*)constructor_adapter_disk(usb);
printf("3.已有Type-C接口,接上手机: ");
typeC->use_typeC_disk(typeC, 20);
typeC->free(typeC);
usb->free(usb);
return 0;
}
运行结果:与预期一致。
四、总结
-
适配器和装饰器模式实现上有一点相似,但是实际应用场景和要解决的问题并不一样,一个是在原有对象的基础上增强功能,另外一个是将两个接口兼容,或者说将一个接口转为另外一个接口。
-
适配器模式的好处就是提高了接口类的复用,增加了不同接口之间的灵活性。
-
虽然C语言是面向过程的编程语言,但是我们在设计程序的时候,可以考虑用面向对象的方式去设计,这样提高我们程序的“高内聚、低耦合”特性,便于维护。
需要C语言实现设计模式代码的小伙伴:在微信公众号【Linux编程用C】后台回复 【designer】 即可获取,不断更新中!
欢迎大家加小C微信【LinuxCodeUseC】,我们一起交流讨论学习!
PS:若大家想看C语言版本的其他设计模式,
请大家 点赞! 转发!关注吧!~~