设计模式详解:7大原则和23种设计模式
目录
- 设计模式7大原则
- 创建型模式(5个)
- 结构型模式(7个)
- 行为型模式(11个)
设计模式7大原则
1. 单一职责原则(Single Responsibility Principle, SRP)
通俗解释:一个类只做一件事,就像一个人只负责一个岗位。
生活例子:
- ❌ 不好的设计:一个员工既要做会计,又要做销售,还要做客服
- ✅ 好的设计:会计专门做账,销售专门卖货,客服专门处理客户问题
为什么重要:如果一个人身兼数职,一旦某个职责出问题,其他职责也会受影响。代码也一样,职责单一,修改时不会影响其他功能。
2. 开闭原则(Open-Closed Principle, OCP)
通俗解释:对扩展开放,对修改关闭。就像手机可以安装新APP(扩展),但不需要拆开手机修改硬件(关闭修改)。
生活例子:
- 手机系统:可以安装新APP(扩展),但不需要修改系统内核(关闭修改)
- 插座:可以插各种电器(扩展),但插座本身不需要改动(关闭修改)
为什么重要:当需要添加新功能时,不需要修改现有代码,只需要添加新代码,降低了引入bug的风险。
3. 里氏替换原则(Liskov Substitution Principle, LSP)
通俗解释:子类可以替换父类,而且替换后程序还能正常工作。就像"苹果是水果"一样,任何需要水果的地方,都可以用苹果。
生活例子:
- 如果"汽车"是"交通工具"的子类,那么任何需要交通工具的地方,都可以用汽车
- 如果"金毛"是"狗"的子类,那么任何需要狗的地方,都可以用金毛
为什么重要:保证继承关系的正确性,子类不能破坏父类的功能。
4. 依赖倒置原则(Dependency Inversion Principle, DIP)
通俗解释:高层模块不应该依赖低层模块,两者都应该依赖抽象。就像看电视,你依赖的是"电视接口",而不是具体的"某品牌电视"。
生活例子:
- 充电:手机依赖的是"USB接口标准",而不是具体的"某品牌充电器"
- 开车:司机依赖的是"方向盘、油门、刹车"这些抽象概念,而不是具体的"某品牌汽车"
为什么重要:降低模块间的耦合,提高代码的可维护性和可扩展性。
5. 接口隔离原则(Interface Segregation Principle, ISP)
通俗解释:不应该强迫客户端依赖它不需要的接口。就像餐厅菜单,不应该把"素食菜单"和"肉食菜单"混在一起。
生活例子:
- ❌ 不好的设计:一个接口包含"飞行"、“游泳”、“跑步”,但鸭子只需要"飞行"和"游泳"
- ✅ 好的设计:分别定义"飞行接口"、“游泳接口”、“跑步接口”,需要什么实现什么
为什么重要:避免接口臃肿,让实现类只实现它需要的功能。
6. 迪米特法则(Law of Demeter, LoD)
通俗解释:只和直接朋友交流,不和陌生人说话。就像你买东西,直接找售货员,而不是找售货员的老板的老板。
生活例子:
- ❌ 不好的设计:A类通过B类获取C类,再通过C类获取D类
- ✅ 好的设计:A类直接和B类交流,B类负责和C类、D类交流
为什么重要:降低类之间的耦合度,提高模块的相对独立性。
7. 合成复用原则(Composite Reuse Principle, CRP)
通俗解释:优先使用组合/聚合,而不是继承。就像组装电脑,用现成的零件组合,而不是自己造一个全新的电脑。
生活例子:
- ❌ 不好的设计:为了用"轮子"功能,继承"汽车"类(太重了)
- ✅ 好的设计:把"轮子"作为"自行车"的一个组成部分(组合)
为什么重要:继承会带来强耦合,组合更灵活,可以动态改变。
创建型模式(5个)
创建型模式关注如何创建对象,让创建过程更灵活、更解耦。
1. 单例模式(Singleton Pattern)
通俗解释:确保一个类只有一个实例,就像一个国家只有一个总统。
生活例子:
- 打印机:一个办公室通常只有一台打印机,大家共用
- 数据库连接:一个应用通常只需要一个数据库连接池
适用场景:
- 需要全局唯一实例的场景
- 需要控制资源访问的场景
C语言实现:
#include<stdio.h>#include<stdlib.h>#include<pthread.h>// 单例结构体typedefstruct{intvalue;}Singleton;// 静态变量,存储唯一实例staticSingleton*instance=NULL;staticpthread_mutex_tmutex=PTHREAD_MUTEX_INITIALIZER;/** * 获取单例实例 * 使用双重检查锁定(Double-Check Locking)确保线程安全 */Singleton*getSingleton(){// 第一次检查:如果实例已存在,直接返回(避免每次都加锁)if(instance==NULL){// 加锁,确保多线程环境下只有一个线程能创建实例pthread_mutex_lock(&mutex);// 第二次检查:再次确认实例是否已创建// 因为可能另一个线程已经创建了实例if(instance==NULL){// 创建唯一实例instance=(Singleton*)malloc(sizeof(Singleton));instance->value=0;printf("创建单例实例\n");}// 释放锁pthread_mutex_unlock(&mutex);}returninstance;}/** * 设置单例的值 */voidsetSingletonValue(intvalue){Singleton*s=getSingleton();s->value=value;}/** * 获取单例的值 */intgetSingletonValue(){Singleton*s=getSingleton();returns->value;}// 测试代码intmain(){// 获取单例实例Singleton*s1=getSingleton();setSingletonValue(100);printf("s1的值: %d\n",getSingletonValue());// 再次获取,应该是同一个实例Singleton*s2=getSingleton();printf("s2的值: %d\n",getSingletonValue());// 修改s2的值setSingletonValue(200);printf("s1的值: %d\n",getSingletonValue());// s1的值也变了,说明是同一个实例return0;}编译运行:
gcc singleton.c -o singleton -lpthread ./singleton2. 工厂方法模式(Factory Method Pattern)
通俗解释:定义一个创建对象的接口,让子类决定实例化哪个类。就像工厂生产产品,不同工厂生产不同产品。
生活例子:
- 汽车工厂:有"轿车工厂"、“SUV工厂”,都继承自"汽车工厂"
- 手机工厂:有"苹果工厂"、“华为工厂”,都继承自"手机工厂"
适用场景:
- 需要创建对象,但不确定具体类型
- 需要扩展新的产品类型
C语言实现:
#include<stdio.h>#include<stdlib.h>// ========== 产品接口 ==========// 定义产品的抽象接口typedefstruct{void(*use)(void*self);// 使用产品的函数指针charname[50];// 产品名称}Product;// 产品使用函数(虚函数)voidproduct_use(void*self){Product*p=(Product*)self;printf("使用产品: %s\n",p->name);}// ========== 具体产品A ==========typedefstruct{Product base;// 继承ProductinttypeA_data;}ProductA;voidproductA_use(void*self){ProductA*pa=(ProductA*)self;printf("使用产品A: %s (类型A数据: %d)\n",pa->base.name,pa->typeA_data);}ProductA*createProductA(){ProductA*pa=(ProductA*)malloc(sizeof(ProductA));pa->base.use=productA_use;pa->base.name[0]='\0';sprintf(pa->base.name,"产品A");pa->typeA_data=100;returnpa;}// ========== 具体产品B ==========typedefstruct{Product base;// 继承ProductchartypeB_data[50];}ProductB;voidproductB_use(void*self){ProductB*pb=(ProductB*)self;printf("使用产品B: %s (类型B数据: %s)\n",pb->base.name,pb->typeB_data);}ProductB*createProductB(){ProductB*pb=(ProductB*)malloc(sizeof(ProductB));pb->base.use=productB_use;pb->base.name[0]='\0';sprintf(pb->base.name,"产品B");sprintf(pb->typeB_data,"类型B的数据");returnpb;}// ========== 工厂接口 ==========// 定义工厂的抽象接口typedefstruct{Product*(*createProduct)(void*self);// 创建产品的函数指针}Factory;// ========== 具体工厂A ==========typedefstruct{Factory base;// 继承Factory}FactoryA;Product*factoryA_createProduct(void*self){printf("工厂A创建产品A\n");return(Product*)createProductA();}FactoryA*createFactoryA(){FactoryA*fa=(FactoryA*)malloc(sizeof(FactoryA));fa->base.createProduct=factoryA_createProduct;returnfa;}// ========== 具体工厂B ==========typedefstruct{Factory base;// 继承Factory}FactoryB;Product*factoryB_createProduct(void*self){printf("工厂B创建产品B\n");return(Product*)createProductB();}FactoryB*createFactoryB(){FactoryB*fb=(FactoryB*)malloc(sizeof(FactoryB));fb->base.createProduct=factoryB_createProduct;returnfb;}// ========== 测试代码 ==========intmain(){// 使用工厂A创建产品FactoryA*factoryA=createFactoryA();Product*product1=factoryA->base.createProduct(factoryA);product1->use(product1);// 使用工厂B创建产品FactoryB*factoryB=createFactoryB();Product*product2=factoryB->base.createProduct(factoryB);product2->use(product2);// 释放内存free(product1);free(product2);free(factoryA);free(factoryB);return0;}编译运行:
gcc factory_method.c -o factory_method ./factory_method3. 抽象工厂模式(Abstract Factory Pattern)
通俗解释:提供一个接口,用于创建相关或依赖对象的家族,而不需要指定具体类。就像家具工厂,可以生产"现代风格"或"古典风格"的整套家具。
生活例子:
- 家具工厂:有"现代风格工厂"(生产现代沙发、现代桌子)和"古典风格工厂"(生产古典沙发、古典桌子)
- UI主题:有"深色主题工厂"和"浅色主题工厂",分别生产深色/浅色的按钮、窗口等
适用场景:
- 需要创建一系列相关对象
- 需要保证产品之间的兼容性
C语言实现:
#include<stdio.h>#include<stdlib.h>#include<string.h>// ========== 产品接口:按钮 ==========typedefstruct{void(*render)(void*self);charname[50];}Button;voidbutton_render(void*self){Button*b=(Button*)self;printf("渲染按钮: %s\n",b->name);}// ========== 产品接口:窗口 ==========typedefstruct{void(*render)(void*self);charname[50];}Window;voidwindow_render(void*self){Window*w=(Window*)self;printf("渲染窗口: %s\n",w->name);}// ========== 具体产品:现代风格按钮 ==========typedefstruct{Button base;}ModernButton;voidmodernButton_render(void*self){ModernButton*mb=(ModernButton*)self;printf("渲染现代风格按钮: %s (简洁、扁平化)\n",mb->base.name);}ModernButton*createModernButton(){ModernButton*mb=(ModernButton*)malloc(sizeof(ModernButton));mb->base.render=modernButton_render;strcpy(mb->base.name,"现代按钮");returnmb;}// ========== 具体产品:现代风格窗口 ==========typedefstruct{Window base;}ModernWindow;voidmodernWindow_render(void*self){ModernWindow*mw=(ModernWindow*)self;printf("渲染现代风格窗口: %s (大边框、圆角)\n",mw->base.name);}ModernWindow*createModernWindow(){ModernWindow*mw=(ModernWindow*)malloc(sizeof(ModernWindow));mw->base.render=modernWindow_render;strcpy(mw->base.name,"现代窗口");returnmw;}// ========== 具体产品:古典风格按钮 ==========typedefstruct{Button base;}ClassicButton;voidclassicButton_render(void*self){ClassicButton*cb=(ClassicButton*)self;printf("渲染古典风格按钮: %s (华丽、装饰性强)\n",cb->base.name);}ClassicButton*createClassicButton(){ClassicButton*cb=(ClassicButton*)malloc(sizeof(ClassicButton));cb->base.render=classicButton_render;strcpy(cb->base.name,"古典按钮");returncb;}// ========== 具体产品:古典风格窗口 ==========typedefstruct{Window base;}ClassicWindow;voidclassicWindow_render(void*self){ClassicWindow*cw=(ClassicWindow*)self;printf("渲染古典风格窗口: %s (小边框、雕花装饰)\n",cw->base.name);}ClassicWindow*createClassicWindow(){ClassicWindow*cw=(ClassicWindow*)malloc(sizeof(ClassicWindow));cw->base.render=classicWindow_render;strcpy(cw->base.name,"古典窗口");returncw;}// ========== 抽象工厂接口 ==========typedefstruct{Button*(*createButton)(void*self);Window*(*createWindow)(void*self);}GUIFactory;// ========== 具体工厂:现代风格工厂 ==========typedefstruct{GUIFactory base;}ModernFactory;Button*modernFactory_createButton(void*self){printf("现代工厂创建现代按钮\n");return(Button*)createModernButton();}Window*modernFactory_createWindow(void*self){printf("现代工厂创建现代窗口\n");return(Window*)createModernWindow();}ModernFactory*createModernFactory(){ModernFactory*mf=(ModernFactory*)malloc(sizeof(ModernFactory));mf->base.createButton=modernFactory_createButton;mf->base.createWindow=modernFactory_createWindow;returnmf;}// ========== 具体工厂:古典风格工厂 ==========typedefstruct{GUIFactory base;}ClassicFactory;Button*classicFactory_createButton(void*self){printf("古典工厂创建古典按钮\n");return(Button*)createClassicButton();}Window*classicFactory_createWindow(void*self){printf("古典工厂创建古典窗口\n");return(Window*)createClassicWindow();}ClassicFactory*createClassicFactory(){ClassicFactory*cf=(ClassicFactory*)malloc(sizeof(ClassicFactory));cf->base.createButton=classicFactory_createButton;cf->base.createWindow=classicFactory_createWindow;returncf;}// ========== 客户端代码 ==========voidcreateUI(GUIFactory*factory){printf("\n=== 创建UI界面 ===\n");Button*button=factory->createButton(factory);Window*window=factory->createWindow(factory);printf("\n=== 渲染UI ===\n");button->render(button);window->render(window);free(button);free(window);}intmain(){// 使用现代风格工厂ModernFactory*modernFactory=createModernFactory();createUI((GUIFactory*)modernFactory);printf("\n");// 使用古典风格工厂ClassicFactory*classicFactory=createClassicFactory();createUI((GUIFactory*)classicFactory);free(modernFactory);free(classicFactory);return0;}编译运行:
gcc abstract_factory.c -o abstract_factory ./abstract_factory4. 建造者模式(Builder Pattern)
通俗解释:将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。就像盖房子,有设计师、施工队,一步步建造。
生活例子:
- 盖房子:先打地基,再建框架,再装修,最后验收
- 点餐:选择主食、配菜、饮料、甜点,最后组成套餐
适用场景:
- 需要创建复杂对象
- 创建过程需要多个步骤
- 需要不同的表示形式
C语言实现:
#include<stdio.h>#include<stdlib.h>#include<string.h>// ========== 产品:房子 ==========typedefstruct{charfoundation[50];// 地基charwalls[50];// 墙壁charroof[50];// 屋顶charinterior[50];// 内饰}House;voidprintHouse(House*house){printf("=== 房子信息 ===\n");printf("地基: %s\n",house->foundation);printf("墙壁: %s\n",house->walls);printf("屋顶: %s\n",house->roof);printf("内饰: %s\n",house->interior);printf("================\n");}// ========== 建造者接口 ==========typedefstruct{void(*buildFoundation)(void*self,constchar*type);void(*buildWalls)(void*self,constchar*type);void(*buildRoof)(void*self,constchar*type);void(*buildInterior)(void*self,constchar*type);House*(*getHouse)(void*self);}HouseBuilder;// ========== 具体建造者:普通房子建造者 ==========typedefstruct{HouseBuilder base;House*house;}NormalHouseBuilder;voidnormalBuilder_buildFoundation(void*self,constchar*type){NormalHouseBuilder*builder=(NormalHouseBuilder*)self;strcpy(builder->house->foundation,type);printf("建造普通房子的地基: %s\n",type);}voidnormalBuilder_buildWalls(void*self,constchar*type){NormalHouseBuilder*builder=(NormalHouseBuilder*)self;strcpy(builder->house->walls,type);printf("建造普通房子的墙壁: %s\n",type);}voidnormalBuilder_buildRoof(void*self,constchar*type){NormalHouseBuilder*builder=(NormalHouseBuilder*)self;strcpy(builder->house->roof,type);printf("建造普通房子的屋顶: %s\n",type);}voidnormalBuilder_buildInterior(void*self,constchar*type){NormalHouseBuilder*builder=(NormalHouseBuilder*)self;strcpy(builder->house->interior,type);printf("建造普通房子的内饰: %s\n",type);}House*normalBuilder_getHouse(void*self){NormalHouseBuilder*builder=(NormalHouseBuilder*)self;returnbuilder->house;}NormalHouseBuilder*createNormalHouseBuilder(){NormalHouseBuilder*builder=(NormalHouseBuilder*)malloc(sizeof(NormalHouseBuilder));builder->house=(House*)malloc(sizeof(House));builder->base.buildFoundation=normalBuilder_buildFoundation;builder->base.buildWalls=normalBuilder_buildWalls;builder->base.buildRoof=normalBuilder_buildRoof;builder->base.buildInterior=normalBuilder_buildInterior;builder->base.getHouse=normalBuilder_getHouse;returnbuilder;}// ========== 具体建造者:豪华房子建造者 ==========typedefstruct{HouseBuilder base;House*house;}LuxuryHouseBuilder;voidluxuryBuilder_buildFoundation(void*self,constchar*type){LuxuryHouseBuilder*builder=(LuxuryHouseBuilder*)self;charluxury_type[100];sprintf(luxury_type,"豪华%s",type);strcpy(builder->house->foundation,luxury_type);printf("建造豪华房子的地基: %s\n",luxury_type);}voidluxuryBuilder_buildWalls(void*self,constchar*type){LuxuryHouseBuilder*builder=(LuxuryHouseBuilder*)self;charluxury_type[100];sprintf(luxury_type,"豪华%s",type);strcpy(builder->house->walls,luxury_type);printf("建造豪华房子的墙壁: %s\n",luxury_type);}voidluxuryBuilder_buildRoof(void*self,constchar*type){LuxuryHouseBuilder*builder=(LuxuryHouseBuilder*)self;charluxury_type[100];sprintf(luxury_type,"豪华%s",type);strcpy(builder->house->roof,luxury_type);printf("建造豪华房子的屋顶: %s\n",luxury_type);}voidluxuryBuilder_buildInterior(void*self,constchar*type){LuxuryHouseBuilder*builder=(LuxuryHouseBuilder*)self;charluxury_type[100];sprintf(luxury_type,"豪华%s",type);strcpy(builder->house->interior,luxury_type);printf("建造豪华房子的内饰: %s\n",luxury_type);}House*luxuryBuilder_getHouse(void*self){LuxuryHouseBuilder*builder=(LuxuryHouseBuilder*)self;returnbuilder->house;}LuxuryHouseBuilder*createLuxuryHouseBuilder(){LuxuryHouseBuilder*builder=(LuxuryHouseBuilder*)malloc(sizeof(LuxuryHouseBuilder));builder->house=(House*)malloc(sizeof(House));builder->base.buildFoundation=luxuryBuilder_buildFoundation;builder->base.buildWalls=luxuryBuilder_buildWalls;builder->base.buildRoof=luxuryBuilder_buildRoof;builder->base.buildInterior=luxuryBuilder_buildInterior;builder->base.getHouse=luxuryBuilder_getHouse;returnbuilder;}// ========== 导演类:负责建造流程 ==========typedefstruct{HouseBuilder*builder;}Director;voiddirector_construct(Director*director){printf("\n=== 开始建造房子 ===\n");// 按照固定流程建造房子director->builder->buildFoundation(director->builder,"混凝土");director->builder->buildWalls(director->builder,"砖墙");director->builder->buildRoof(director->builder,"瓦片");director->builder->buildInterior(director->builder,"简装");printf("=== 房子建造完成 ===\n\n");}Director*createDirector(HouseBuilder*builder){Director*director=(Director*)malloc(sizeof(Director));director->builder=builder;returndirector;}intmain(){// 建造普通房子NormalHouseBuilder*normalBuilder=createNormalHouseBuilder();Director*director1=createDirector((HouseBuilder*)normalBuilder);director_construct(director1);House*normalHouse=normalBuilder->base.getHouse(normalBuilder);printHouse(normalHouse);// 建造豪华房子LuxuryHouseBuilder*luxuryBuilder=createLuxuryHouseBuilder();Director*director2=createDirector((HouseBuilder*)luxuryBuilder);director_construct(director2);House*luxuryHouse=luxuryBuilder->base.getHouse(luxuryBuilder);printHouse(luxuryHouse);// 释放内存free(normalHouse);free(luxuryHouse);free(normalBuilder);free(luxuryBuilder);free(director1);free(director2);return0;}编译运行:
gcc builder.c -o builder ./builder5. 原型模式(Prototype Pattern)
通俗解释:通过复制现有实例来创建新实例,而不是新建。就像复印机,可以快速复制文档。
生活例子:
- 复印机:复制一份文档
- 克隆:克隆羊多莉
- 模板:用模板快速创建相似对象
适用场景:
- 创建对象成本高(如需要大量计算或数据库查询)
- 需要创建相似对象
- 需要动态配置对象
C语言实现:
#include<stdio.h>#include<stdlib.h>#include<string.h>// ========== 原型接口 ==========typedefstruct{void*(*clone)(void*self);// 克隆函数void(*display)(void*self);// 显示函数charname[50];intid;}Prototype;// ========== 具体原型:简历 ==========typedefstruct{Prototype base;char*workExperience;// 工作经验intage;}Resume;// 克隆函数:深拷贝void*resume_clone(void*self){Resume*original=(Resume*)self;Resume*copy=(Resume*)malloc(sizeof(Resume));// 复制基本信息copy->base.clone=original->base.clone;copy->base.display=original->base.display;strcpy(copy->base.name,original->base.name);copy->base.id=original->base.id+1000;// 新ID// 深拷贝工作经验(字符串)if(original->workExperience){intlen=strlen(original->workExperience);copy->workExperience=(char*)malloc(len+1);strcpy(copy->workExperience,original->workExperience);}else{copy->workExperience=NULL;}copy->age=original->age;printf("克隆简历: %s (新ID: %d)\n",copy->base.name,copy->base.id);returncopy;}// 显示函数voidresume_display(void*self){Resume*r=(Resume*)self;printf("=== 简历信息 ===\n");printf("姓名: %s\n",r->base.name);printf("ID: %d\n",r->base.id);printf("年龄: %d\n",r->age);printf("工作经验: %s\n",r->workExperience?r->workExperience:"无");printf("===============\n");}// 创建简历原型Resume*createResume(constchar*name,intage,constchar*workExp){Resume*r=(Resume*)malloc(sizeof(Resume));r->base.clone=resume_clone;r->base.display=resume_display;strcpy(r->base.name,name);r->base.id=1001;r->age=age;if(workExp){intlen=strlen(workExp);r->workExperience=(char*)malloc(len+1);strcpy(r->workExperience,workExp);}else{r->workExperience=NULL;}returnr;}// 释放简历内存voidfreeResume(Resume*r){if(r){if(r->workExperience){free(r->workExperience);}free(r);}}// ========== 原型管理器 ==========typedefstruct{Prototype*prototypes[10];// 存储原型intcount;}PrototypeManager;PrototypeManager*createPrototypeManager(){PrototypeManager*pm=(PrototypeManager*)malloc(sizeof(PrototypeManager));pm->count=0;returnpm;}// 注册原型voidregisterPrototype(PrototypeManager*pm,Prototype*proto){if(pm->count<10){pm->prototypes[pm->count++]=proto;printf("注册原型: %s\n",proto->name);}}// 获取原型副本Prototype*getPrototype(PrototypeManager*pm,intindex){if(index>=0&&index<pm->count){returnpm->prototypes[index]->clone(pm->prototypes[index]);}returnNULL;}intmain(){// 创建原始简历Resume*originalResume=createResume("张三",25,"5年Java开发经验");printf("\n=== 原始简历 ===\n");originalResume->base.display(originalResume);// 使用原型模式克隆简历printf("\n=== 克隆简历1 ===\n");Resume*clonedResume1=(Resume*)originalResume->base.clone(originalResume);// 修改克隆后的简历strcpy(clonedResume1->base.name,"李四");clonedResume1->age=28;clonedResume1->base.display(clonedResume1);printf("\n=== 克隆简历2 ===\n");Resume*clonedResume2=(Resume*)originalResume->base.clone(originalResume);strcpy(clonedResume2->base.name,"王五");clonedResume2->age=30;if(clonedResume2->workExperience){free(clonedResume2->workExperience);clonedResume2->workExperience=(char*)malloc(50);strcpy(clonedResume2->workExperience,"3年Python开发经验");}clonedResume2->base.display(clonedResume2);// 使用原型管理器printf("\n=== 使用原型管理器 ===\n");PrototypeManager*pm=createPrototypeManager();registerPrototype(pm,(Prototype*)originalResume);Resume*clonedResume3=(Resume*)getPrototype(pm,0);clonedResume3->base.display(clonedResume3);// 释放内存freeResume(originalResume);freeResume(clonedResume1);freeResume(clonedResume2);freeResume(clonedResume3);free(pm);return0;}编译运行:
gcc prototype.c -o prototype ./prototype总结:创建型模式
创建型模式帮助我们更灵活地创建对象:
- 单例模式:确保只有一个实例
- 工厂方法模式:让子类决定创建什么对象
- 抽象工厂模式:创建一系列相关对象
- 建造者模式:分步骤创建复杂对象
- 原型模式:通过复制创建对象
每种模式都解决了不同的对象创建问题,选择合适的模式可以让代码更清晰、更易维护。
设计模式详解:结构型模式(7个)
结构型模式关注如何组合类和对象,形成更大的结构。
1. 适配器模式(Adapter Pattern)
通俗解释:让不兼容的接口能够一起工作。就像电源适配器,让不同国家的插头都能用。
生活例子:
- 电源适配器:把220V电压转换成110V,让美国电器在中国能用
- USB转HDMI:让USB接口的设备能连接HDMI显示器
- 翻译器:让说不同语言的人能交流
适用场景:
- 需要使用现有类,但接口不兼容
- 需要统一多个不同接口
C语言实现:
#include<stdio.h>#include<stdlib.h>#include<string.h>// ========== 目标接口:新系统需要的接口 ==========// 这是客户端期望的接口typedefstruct{void(*request)(void*self);// 请求函数}Target;voidtarget_request(void*self){printf("目标接口:处理标准请求\n");}// ========== 被适配者:旧系统(不兼容的接口) ==========// 这是已经存在的类,但接口不兼容typedefstruct{void(*specificRequest)(void*self);// 特殊请求函数}Adaptee;voidadaptee_specificRequest(void*self){printf("被适配者:处理特殊请求(旧接口)\n");}Adaptee*createAdaptee(){Adaptee*a=(Adaptee*)malloc(sizeof(Adaptee));a->specificRequest=adaptee_specificRequest;returna;}// ========== 适配器:连接目标接口和被适配者 ==========// 适配器实现了目标接口,内部使用被适配者typedefstruct{Target base;// 继承目标接口Adaptee*adaptee;// 包含被适配者}Adapter;voidadapter_request(void*self){Adapter*adapter=(Adapter*)self;printf("适配器:将标准请求转换为特殊请求\n");// 调用被适配者的方法,实现适配adapter->adaptee->specificRequest(adapter->adaptee);}Adapter*createAdapter(Adaptee*adaptee){Adapter*adapter=(Adapter*)malloc(sizeof(Adapter));adapter->base.request=adapter_request;adapter->adaptee=adaptee;returnadapter;}// ========== 客户端代码 ==========voidclientCode(Target*target){printf("客户端:调用目标接口\n");target->request(target);}intmain(){printf("=== 适配器模式演示 ===\n\n");// 创建被适配者(旧系统)Adaptee*adaptee=createAdaptee();// 创建适配器,将旧系统适配到新接口Adapter*adapter=createAdapter(adaptee);// 客户端使用目标接口(新接口)// 适配器让旧系统看起来像新接口clientCode((Target*)adapter);// 释放内存free(adaptee);free(adapter);return0;}编译运行:
gcc adapter.c -o adapter ./adapter2. 桥接模式(Bridge Pattern)
通俗解释:将抽象和实现分离,使它们可以独立变化。就像遥控器和电视,遥控器(抽象)可以控制不同品牌的电视(实现)。
生活例子:
- 遥控器和电视:遥控器是抽象,不同品牌电视是实现
- 画笔和颜色:画笔是抽象,不同颜色是实现
- 操作系统和驱动程序:操作系统是抽象,不同硬件驱动是实现
适用场景:
- 需要在运行时切换实现
- 需要避免抽象和实现的绑定
C语言实现:
#include<stdio.h>#include<stdlib.h>#include<string.h>// ========== 实现接口:颜色(实现部分) ==========// 这是实现部分的抽象typedefstruct{void(*applyColor)(void*self);// 应用颜色charcolorName[50];}Color;voidcolor_applyColor(void*self){Color*c=(Color*)self;printf("应用颜色: %s\n",c->colorName);}// ========== 具体实现:红色 ==========typedefstruct{Color base;}RedColor;voidredColor_applyColor(void*self){RedColor*rc=(RedColor*)self;printf("应用红色\n");}RedColor*createRedColor(){RedColor*rc=(RedColor*)malloc(sizeof(RedColor));rc->base.applyColor=redColor_applyColor;strcpy(rc->base.colorName,"红色");returnrc;}// ========== 具体实现:蓝色 ==========typedefstruct{Color base;}BlueColor;voidblueColor_applyColor(void*self){BlueColor*bc=(BlueColor*)self;printf("应用蓝色\n");}BlueColor*createBlueColor(){BlueColor*bc=(BlueColor*)malloc(sizeof(BlueColor));bc->base.applyColor=blueColor_applyColor;strcpy(bc->base.colorName,"蓝色");returnbc;}// ========== 抽象类:形状(抽象部分) ==========// 这是抽象部分,包含对实现的引用typedefstruct{Color*color;// 桥接:持有实现部分的引用void(*draw)(void*self);// 绘制函数}Shape;voidshape_draw(void*self){Shape*s=(Shape*)self;printf("绘制形状");if(s->color){printf(",使用");s->color->applyColor(s->color);}}// ========== 具体抽象:圆形 ==========typedefstruct{Shape base;}Circle;voidcircle_draw(void*self){Circle*c=(Circle*)self;printf("绘制圆形");if(c->base.color){printf(",使用");c->base.color->applyColor(c->base.color);}printf("\n");}Circle*createCircle(Color*color){Circle*circle=(Circle*)malloc(sizeof(Circle));circle->base.color=color;// 桥接:设置实现circle->base.draw=circle_draw;returncircle;}// ========== 具体抽象:方形 ==========typedefstruct{Shape base;}Square;voidsquare_draw(void*self){Square*s=(Square*)self;printf("绘制方形");if(s->base.color){printf(",使用");s->base.color->applyColor(s->base.color);}printf("\n");}Square*createSquare(Color*color){Square*square=(Square*)malloc(sizeof(Square));square->base.color=color;// 桥接:设置实现square->base.draw=square_draw;returnsquare;}intmain(){printf("=== 桥接模式演示 ===\n\n");// 创建实现:红色和蓝色RedColor*red=createRedColor();BlueColor*blue=createBlueColor();// 创建抽象:圆形和方形,并桥接到不同的颜色实现printf("--- 红色圆形 ---\n");Circle*redCircle=createCircle((Color*)red);redCircle->base.draw(redCircle);printf("\n--- 蓝色圆形 ---\n");Circle*blueCircle=createCircle((Color*)blue);blueCircle->base.draw(blueCircle);printf("\n--- 红色方形 ---\n");Square*redSquare=createSquare((Color*)red);redSquare->base.draw(redSquare);printf("\n--- 蓝色方形 ---\n");Square*blueSquare=createSquare((Color*)blue);blueSquare->base.draw(blueSquare);// 释放内存free(red);free(blue);free(redCircle);free(blueCircle);free(redSquare);free(blueSquare);return0;}编译运行:
gcc bridge.c -o bridge ./bridge3. 组合模式(Composite Pattern)
通俗解释:将对象组合成树形结构,使单个对象和组合对象使用一致。就像文件夹和文件,文件夹可以包含文件,也可以包含其他文件夹。
生活例子:
- 文件系统:文件夹可以包含文件或子文件夹
- 组织结构:部门可以包含员工或子部门
- 菜单系统:菜单可以包含菜单项或子菜单
适用场景:
- 需要表示部分-整体层次结构
- 需要统一处理单个对象和组合对象
C语言实现:
#include<stdio.h>#include<stdlib.h>#include<string.h>// ========== 组件接口 ==========// 这是组合模式的核心接口,既可以表示叶子节点,也可以表示组合节点typedefstructComponent{charname[100];void(*operation)(structComponent*self);// 操作函数void(*add)(structComponent*self,structComponent*child);// 添加子组件void(*remove)(structComponent*self,structComponent*child);// 移除子组件structComponent*(*getChild)(structComponent*self,intindex);// 获取子组件}Component;// ========== 叶子节点:文件 ==========// 叶子节点没有子节点typedefstruct{Component base;intsize;// 文件大小}File;voidfile_operation(Component*self){File*f=(File*)self;printf("文件: %s (大小: %d KB)\n",f->base.name,f->size);}voidfile_add(Component*self,Component*child){printf("错误:文件不能添加子组件\n");}voidfile_remove(Component*self,Component*child){printf("错误:文件不能移除子组件\n");}Component*file_getChild(Component*self,intindex){returnNULL;// 文件没有子节点}File*createFile(constchar*name,intsize){File*f=(File*)malloc(sizeof(File));strcpy(f->base.name,name);f->size=size;f->base.operation=file_operation;f->base.add=file_add;f->base.remove=file_remove;f->base.getChild=file_getChild;returnf;}// ========== 组合节点:文件夹 ==========// 组合节点可以包含子组件typedefstruct{Component base;Component*children[100];// 子组件数组intchildCount;// 子组件数量}Folder;voidfolder_operation(Component*self){Folder*folder=(Folder*)self;printf("文件夹: %s (包含 %d 个项目)\n",folder->base.name,folder->childCount);// 递归操作所有子组件for(inti=0;i<folder->childCount;i++){printf(" ");folder->children[i]->operation(folder->children[i]);}}voidfolder_add(Component*self,Component*child){Folder*folder=(Folder*)self;if(folder->childCount<100){folder->children[folder->childCount++]=child;printf("添加 %s 到 %s\n",child->name,folder->base.name);}}voidfolder_remove(Component*self,Component*child){Folder*folder=(Folder*)self;for(inti=0;i<folder->childCount;i++){if(folder->children[i]==child){// 移除子组件for(intj=i;j<folder->childCount-1;j++){folder->children[j]=folder->children[j+1];}folder->childCount--;printf("从 %s 移除 %s\n",folder->base.name,child->name);return;}}}Component*folder_getChild(Component*self,intindex){Folder*folder=(Folder*)self;if(index>=0&&index<folder->childCount){returnfolder->children[index];}returnNULL;}Folder*createFolder(constchar*name){Folder*folder=(Folder*)malloc(sizeof(Folder));strcpy(folder->base.name,name);folder->childCount=0;folder->base.operation=folder_operation;folder->base.add=folder_add;folder->base.remove=folder_remove;folder->base.getChild=folder_getChild;returnfolder;}intmain(){printf("=== 组合模式演示 ===\n\n");// 创建根文件夹Folder*root=createFolder("根目录");// 创建文件File*file1=createFile("文档.txt",10);File*file2=createFile("图片.jpg",500);// 创建子文件夹Folder*subFolder=createFolder("子文件夹");// 创建子文件夹中的文件File*file3=createFile("数据.csv",50);File*file4=createFile("报告.pdf",200);// 构建树形结构printf("--- 构建文件系统结构 ---\n");root->base.add((Component*)root,(Component*)file1);root->base.add((Component*)root,(Component*)file2);root->base.add((Component*)root,(Component*)subFolder);subFolder->base.add((Component*)subFolder,(Component*)file3);subFolder->base.add((Component*)subFolder,(Component*)file4);printf("\n--- 遍历文件系统 ---\n");// 统一操作:无论是文件还是文件夹,都用同样的接口root->base.operation((Component*)root);// 释放内存(简化版,实际应该递归释放)free(file1);free(file2);free(file3);free(file4);free(subFolder);free(root);return0;}编译运行:
gcc composite.c -o composite ./composite4. 装饰器模式(Decorator Pattern)
通俗解释:动态地给对象添加新功能,比继承更灵活。就像给手机加保护壳、贴膜、挂件,一层层装饰。
生活例子:
- 手机装饰:手机 + 保护壳 + 贴膜 + 挂件
- 咖啡:咖啡 + 糖 + 牛奶 + 奶油
- 披萨:基础披萨 + 芝士 + 香肠 + 蔬菜
适用场景:
- 需要动态添加功能
- 不想使用继承扩展功能
C语言实现:
#include<stdio.h>#include<stdlib.h>#include<string.h>// ========== 组件接口:咖啡 ==========typedefstruct{chardescription[100];int(*cost)(void*self);// 计算价格void(*getDescription)(void*self,char*buffer);// 获取描述}Coffee;intcoffee_cost(void*self){return0;}voidcoffee_getDescription(void*self,char*buffer){Coffee*c=(Coffee*)self;strcpy(buffer,c->description);}// ========== 具体组件:基础咖啡 ==========typedefstruct{Coffee base;}SimpleCoffee;intsimpleCoffee_cost(void*self){return10;// 基础咖啡10元}voidsimpleCoffee_getDescription(void*self,char*buffer){strcpy(buffer,"基础咖啡");}SimpleCoffee*createSimpleCoffee(){SimpleCoffee*sc=(SimpleCoffee*)malloc(sizeof(SimpleCoffee));strcpy(sc->base.description,"基础咖啡");sc->base.cost=simpleCoffee_cost;sc->base.getDescription=simpleCoffee_getDescription;returnsc;}// ========== 装饰器基类 ==========typedefstruct{Coffee base;Coffee*coffee;// 被装饰的咖啡}CoffeeDecorator;// ========== 具体装饰器:加糖 ==========typedefstruct{CoffeeDecorator base;}SugarDecorator;intsugarDecorator_cost(void*self){SugarDecorator*sd=(SugarDecorator*)self;returnsd->base.coffee->cost(sd->base.coffee)+2;// 加2元}voidsugarDecorator_getDescription(void*self,char*buffer){SugarDecorator*sd=(SugarDecorator*)self;chartemp[200];sd->base.coffee->getDescription(sd->base.coffee,temp);sprintf(buffer,"%s + 糖",temp);}SugarDecorator*createSugarDecorator(Coffee*coffee){SugarDecorator*sd=(SugarDecorator*)malloc(sizeof(SugarDecorator));sd->base.coffee=coffee;sd->base.cost=sugarDecorator_cost;sd->base.getDescription=sugarDecorator_getDescription;returnsd;}// ========== 具体装饰器:加牛奶 ==========typedefstruct{CoffeeDecorator base;}MilkDecorator;intmilkDecorator_cost(void*self){MilkDecorator*md=(MilkDecorator*)self;returnmd->base.coffee->cost(md->base.coffee)+3;// 加3元}voidmilkDecorator_getDescription(void*self,char*buffer){MilkDecorator*md=(MilkDecorator*)self;chartemp[200];md->base.coffee->getDescription(md->base.coffee,temp);sprintf(buffer,"%s + 牛奶",temp);}MilkDecorator*createMilkDecorator(Coffee*coffee){MilkDecorator*md=(MilkDecorator*)malloc(sizeof(MilkDecorator));md->base.coffee=coffee;md->base.cost=milkDecorator_cost;md->base.getDescription=milkDecorator_getDescription;returnmd;}// ========== 具体装饰器:加奶油 ==========typedefstruct{CoffeeDecorator base;}CreamDecorator;intcreamDecorator_cost(void*self){CreamDecorator*cd=(CreamDecorator*)self;returncd->base.coffee->cost(cd->base.coffee)+4;// 加4元}voidcreamDecorator_getDescription(void*self,char*buffer){CreamDecorator*cd=(CreamDecorator*)self;chartemp[200];cd->base.coffee->getDescription(cd->base.coffee,temp);sprintf(buffer,"%s + 奶油",temp);}CreamDecorator*createCreamDecorator(Coffee*coffee){CreamDecorator*cd=(CreamDecorator*)malloc(sizeof(CreamDecorator));cd->base.coffee=coffee;cd->base.cost=creamDecorator_cost;cd->base.getDescription=creamDecorator_getDescription;returncd;}intmain(){printf("=== 装饰器模式演示 ===\n\n");// 创建基础咖啡SimpleCoffee*coffee=createSimpleCoffee();chardesc[200];coffee->base.getDescription(&coffee->base,desc);printf("订单1: %s\n",desc);printf("价格: %d元\n\n",coffee->base.cost(&coffee->base));// 装饰:加糖SugarDecorator*coffeeWithSugar=createSugarDecorator((Coffee*)coffee);coffeeWithSugar->base.getDescription((Coffee*)coffeeWithSugar,desc);printf("订单2: %s\n",desc);printf("价格: %d元\n\n",coffeeWithSugar->base.cost((Coffee*)coffeeWithSugar));// 装饰:加糖 + 牛奶MilkDecorator*coffeeWithSugarMilk=createMilkDecorator((Coffee*)coffeeWithSugar);coffeeWithSugarMilk->base.getDescription((Coffee*)coffeeWithSugarMilk,desc);printf("订单3: %s\n",desc);printf("价格: %d元\n\n",coffeeWithSugarMilk->base.cost((Coffee*)coffeeWithSugarMilk));// 装饰:加糖 + 牛奶 + 奶油CreamDecorator*coffeeWithAll=createCreamDecorator((Coffee*)coffeeWithSugarMilk);coffeeWithAll->base.getDescription((Coffee*)coffeeWithAll,desc);printf("订单4: %s\n",desc);printf("价格: %d元\n\n",coffeeWithAll->base.cost((Coffee*)coffeeWithAll));// 释放内存(简化版)free(coffee);free(coffeeWithSugar);free(coffeeWithSugarMilk);free(coffeeWithAll);return0;}编译运行:
gcc decorator.c -o decorator ./decorator5. 外观模式(Facade Pattern)
通俗解释:为复杂子系统提供一个简单接口。就像一键启动电脑,不需要知道CPU、内存、硬盘如何协调工作。
生活例子:
- 一键启动:一键启动电脑,隐藏了复杂的启动过程
- 银行ATM:简单的界面,背后是复杂的银行系统
- 智能家居:一个APP控制所有设备,隐藏了复杂的通信协议
适用场景:
- 需要简化复杂子系统
- 需要解耦客户端和子系统
C语言实现:
#include<stdio.h>#include<stdlib.h>#include<string.h>// ========== 子系统1:CPU ==========typedefstruct{void(*start)(void);void(*stop)(void);}CPU;voidcpu_start(void){printf("CPU: 启动\n");}voidcpu_stop(void){printf("CPU: 停止\n");}CPU*createCPU(){CPU*cpu=(CPU*)malloc(sizeof(CPU));cpu->start=cpu_start;cpu->stop=cpu_stop;returncpu;}// ========== 子系统2:内存 ==========typedefstruct{void(*load)(void);void(*unload)(void);}Memory;voidmemory_load(void){printf("内存: 加载数据\n");}voidmemory_unload(void){printf("内存: 卸载数据\n");}Memory*createMemory(){Memory*mem=(Memory*)malloc(sizeof(Memory));mem->load=memory_load;mem->unload=memory_unload;returnmem;}// ========== 子系统3:硬盘 ==========typedefstruct{void(*read)(void);void(*write)(void);}HardDrive;voidhardDrive_read(void){printf("硬盘: 读取数据\n");}voidhardDrive_write(void){printf("硬盘: 写入数据\n");}HardDrive*createHardDrive(){HardDrive*hd=(HardDrive*)malloc(sizeof(HardDrive));hd->read=hardDrive_read;hd->write=hardDrive_write;returnhd;}// ========== 外观类:计算机 ==========// 外观类封装了子系统的复杂操作,提供简单接口typedefstruct{CPU*cpu;Memory*memory;HardDrive*hardDrive;void(*startComputer)(void*self);void(*stopComputer)(void*self);}Computer;voidcomputer_startComputer(void*self){Computer*comp=(Computer*)self;printf("=== 启动计算机 ===\n");comp->cpu->start();comp->memory->load();comp->hardDrive->read();printf("计算机启动完成!\n\n");}voidcomputer_stopComputer(void*self){Computer*comp=(Computer*)self;printf("=== 关闭计算机 ===\n");comp->hardDrive->write();comp->memory->unload();comp->cpu->stop();printf("计算机关闭完成!\n\n");}Computer*createComputer(){Computer*comp=(Computer*)malloc(sizeof(Computer));comp->cpu=createCPU();comp->memory=createMemory();comp->hardDrive=createHardDrive();comp->startComputer=computer_startComputer;comp->stopComputer=computer_stopComputer;returncomp;}voidfreeComputer(Computer*comp){if(comp){free(comp->cpu);free(comp->memory);free(comp->hardDrive);free(comp);}}intmain(){printf("=== 外观模式演示 ===\n\n");// 创建计算机(外观对象)Computer*computer=createComputer();// 客户端只需要调用简单接口,不需要知道子系统细节printf("--- 用户操作:启动电脑 ---\n");computer->startComputer(computer);printf("--- 用户操作:关闭电脑 ---\n");computer->stopComputer(computer);// 如果不使用外观模式,客户端需要这样操作(复杂):printf("--- 不使用外观模式(复杂) ---\n");CPU*cpu=createCPU();Memory*mem=createMemory();HardDrive*hd=createHardDrive();cpu->start();mem->load();hd->read();hd->write();mem->unload();cpu->stop();// 释放内存freeComputer(computer);free(cpu);free(mem);free(hd);return0;}编译运行:
gcc facade.c -o facade ./facade6. 享元模式(Flyweight Pattern)
通俗解释:通过共享相同数据来减少内存使用。就像图书馆,多个人可以共享同一本书,而不需要每人买一本。
生活例子:
- 图书馆:多个人共享同一本书
- 字体:多个字符共享同一字体对象
- 游戏:多个敌人共享同一模型和纹理
适用场景:
- 需要创建大量相似对象
- 对象的大部分状态可以共享
C语言实现:
#include<stdio.h>#include<stdlib.h>#include<string.h>// ========== 享元接口:字符 ==========typedefstruct{charsymbol;// 字符(内部状态,可共享)void(*display)(void*self,intx,inty);// 显示函数}Character;// ========== 具体享元:具体字符 ==========typedefstruct{Character base;charfont[50];// 字体(内部状态,可共享)intsize;// 大小(内部状态,可共享)}ConcreteCharacter;voidcharacter_display(void*self,intx,inty){ConcreteCharacter*cc=(ConcreteCharacter*)self;printf("显示字符 '%c' (字体: %s, 大小: %d) 在位置 (%d, %d)\n",cc->base.symbol,cc->font,cc->size,x,y);}ConcreteCharacter*createCharacter(charsymbol,constchar*font,intsize){ConcreteCharacter*cc=(ConcreteCharacter*)malloc(sizeof(ConcreteCharacter));cc->base.symbol=symbol;strcpy(cc->font,font);cc->size=size;cc->base.display=character_display;returncc;}// ========== 享元工厂:管理享元对象 ==========typedefstruct{ConcreteCharacter*characters[100];// 享元对象池intcount;}CharacterFactory;CharacterFactory*createCharacterFactory(){CharacterFactory*factory=(CharacterFactory*)malloc(sizeof(CharacterFactory));factory->count=0;returnfactory;}// 获取享元对象(如果不存在则创建)ConcreteCharacter*getCharacter(CharacterFactory*factory,charsymbol,constchar*font,intsize){// 查找是否已存在相同的享元对象for(inti=0;i<factory->count;i++){ConcreteCharacter*cc=factory->characters[i];if(cc->base.symbol==symbol&&strcmp(cc->font,font)==0&&cc->size==size){printf("复用享元对象: '%c'\n",symbol);returncc;// 返回已存在的对象}}// 不存在,创建新的享元对象printf("创建新享元对象: '%c'\n",symbol);ConcreteCharacter*cc=createCharacter(symbol,font,size);factory->characters[factory->count++]=cc;returncc;}// ========== 外部状态:位置信息 ==========// 这些是外部状态,不存储在享元对象中typedefstruct{Character*character;// 享元对象引用intx;// 外部状态:X坐标inty;// 外部状态:Y坐标}CharacterContext;CharacterContext*createCharacterContext(Character*ch,intx,inty){CharacterContext*ctx=(CharacterContext*)malloc(sizeof(CharacterContext));ctx->character=ch;ctx->x=x;ctx->y=y;returnctx;}voiddisplayContext(CharacterContext*ctx){ctx->character->display(ctx->character,ctx->x,ctx->y);}intmain(){printf("=== 享元模式演示 ===\n\n");// 创建享元工厂CharacterFactory*factory=createCharacterFactory();// 创建字符上下文(包含外部状态)printf("--- 创建文本 ---\n");CharacterContext*contexts[10];intcontextCount=0;// 创建多个字符,但相同字符会共享享元对象contexts[contextCount++]=createCharacterContext((Character*)getCharacter(factory,'H',"Arial",12),0,0);contexts[contextCount++]=createCharacterContext((Character*)getCharacter(factory,'e',"Arial",12),10,0);contexts[contextCount++]=createCharacterContext((Character*)getCharacter(factory,'l',"Arial",12),20,0);contexts[contextCount++]=createCharacterContext((Character*)getCharacter(factory,'l',"Arial",12),30,0);// 复用'l'contexts[contextCount++]=createCharacterContext((Character*)getCharacter(factory,'o',"Arial",12),40,0);printf("\n--- 显示文本 ---\n");for(inti=0;i<contextCount;i++){displayContext(contexts[i]);}printf("\n--- 统计信息 ---\n");printf("文本长度: %d 个字符\n",contextCount);printf("实际创建的享元对象: %d 个\n",factory->count);printf("节省内存: %d 个对象\n",contextCount-factory->count);// 释放内存(简化版)for(inti=0;i<contextCount;i++){free(contexts[i]);}for(inti=0;i<factory->count;i++){free(factory->characters[i]);}free(factory);return0;}编译运行:
gcc flyweight.c -o flyweight ./flyweight7. 代理模式(Proxy Pattern)
通俗解释:为其他对象提供代理以控制对这个对象的访问。就像代购,你通过代购买东西,代购控制你和商家的交互。
生活例子:
- 代购:代购代理你购买商品
- 门禁卡:门禁卡代理你开门
- 缓存代理:缓存代理数据库,减少数据库访问
适用场景:
- 需要控制对象访问
- 需要延迟加载
- 需要添加额外功能(如缓存、日志)
C语言实现:
#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>// 用于sleep函数// ========== 主题接口:图像 ==========typedefstruct{void(*display)(void*self);// 显示函数charfilename[100];}Image;voidimage_display(void*self){Image*img=(Image*)self;printf("显示图像: %s\n",img->filename);}// ========== 真实主题:真实图像 ==========// 这是实际的对象,可能创建成本很高typedefstruct{Image base;}RealImage;voidrealImage_display(void*self){RealImage*ri=(RealImage*)self;printf("从磁盘加载图像: %s\n",ri->base.filename);sleep(1);// 模拟加载时间printf("显示真实图像: %s\n",ri->base.filename);}RealImage*createRealImage(constchar*filename){RealImage*ri=(RealImage*)malloc(sizeof(RealImage));strcpy(ri->base.filename,filename);ri->base.display=realImage_display;printf("创建真实图像对象: %s\n",filename);returnri;}// ========== 代理:图像代理 ==========// 代理控制对真实图像的访问typedefstruct{Image base;RealImage*realImage;// 真实图像的引用intloaded;// 是否已加载}ProxyImage;voidproxyImage_display(void*self){ProxyImage*proxy=(ProxyImage*)self;// 延迟加载:只有在需要时才创建真实对象if(!proxy->loaded){printf("代理:延迟加载图像\n");proxy->realImage=createRealImage(proxy->base.filename);proxy->loaded=1;}// 调用真实对象的显示方法proxy->realImage->base.display(&proxy->realImage->base);}ProxyImage*createProxyImage(constchar*filename){ProxyImage*proxy=(ProxyImage*)malloc(sizeof(ProxyImage));strcpy(proxy->base.filename,filename);proxy->base.display=proxyImage_display;proxy->realImage=NULL;proxy->loaded=0;printf("创建图像代理: %s\n",filename);returnproxy;}intmain(){printf("=== 代理模式演示 ===\n\n");// 创建代理对象(此时真实对象还未创建)ProxyImage*proxy1=createProxyImage("photo1.jpg");ProxyImage*proxy2=createProxyImage("photo2.jpg");printf("\n--- 第一次显示图像1 ---\n");// 第一次调用:代理会创建真实对象proxy1->base.display(proxy1);printf("\n--- 第一次显示图像2 ---\n");proxy2->base.display(proxy2);printf("\n--- 第二次显示图像1(已缓存) ---\n");// 第二次调用:直接使用已创建的真实对象proxy1->base.display(proxy1);// 释放内存if(proxy1->realImage){free(proxy1->realImage);}if(proxy2->realImage){free(proxy2->realImage);}free(proxy1);free(proxy2);return0;}编译运行:
gcc proxy.c -o proxy ./proxy总结:结构型模式
结构型模式帮助我们组合类和对象,形成更大的结构:
- 适配器模式:让不兼容的接口能够一起工作
- 桥接模式:将抽象和实现分离
- 组合模式:统一处理单个对象和组合对象
- 装饰器模式:动态添加功能
- 外观模式:简化复杂子系统
- 享元模式:共享数据减少内存
- 代理模式:控制对象访问
每种模式都解决了不同的结构问题,让代码更灵活、更易维护。
设计模式详解:行为型模式(11个)
行为型模式关注对象之间的通信和职责分配。
1. 责任链模式(Chain of Responsibility Pattern)
通俗解释:将请求沿着处理者链传递,直到有处理者处理它。就像请假,先找组长,组长处理不了找经理,经理处理不了找总经理。
生活例子:
- 请假流程:员工 → 组长 → 经理 → 总经理
- 客服系统:一级客服 → 二级客服 → 三级客服
- 异常处理:try-catch链式处理
适用场景:
- 有多个对象可以处理请求
- 不确定哪个对象处理请求
- 需要动态指定处理者
C语言实现:
#include<stdio.h>#include<stdlib.h>#include<string.h>// ========== 请求类型 ==========typedefstruct{intamount;// 金额chartype[50];// 类型}Request;Request*createRequest(intamount,constchar*type){Request*req=(Request*)malloc(sizeof(Request));req->amount=amount;strcpy(req->type,type);returnreq;}// ========== 处理者接口 ==========typedefstructHandler{structHandler*next;// 下一个处理者intlimit;// 处理权限上限charname[50];// 处理者名称int(*handle)(structHandler*self,Request*request);// 处理函数void(*setNext)(structHandler*self,structHandler*next);// 设置下一个处理者}Handler;// 设置下一个处理者voidhandler_setNext(Handler*self,Handler*next){self->next=next;}// 处理请求(模板方法)inthandler_handle(Handler*self,Request*request){// 如果当前处理者可以处理if(request->amount<=self->limit){printf("%s 处理了请求: %s, 金额: %d\n",self->name,request->type,request->amount);return1;// 处理成功}// 如果不能处理,传递给下一个处理者if(self->next!=NULL){printf("%s 无法处理,传递给下一个处理者\n",self->name);returnself->next->handle(self->next,request);}// 没有处理者能处理printf("没有处理者能处理该请求\n");return0;}// ========== 具体处理者:组长 ==========typedefstruct{Handler base;}GroupLeader;intgroupLeader_handle(Handler*self,Request*request){self->limit=1000;// 组长最多处理1000元strcpy(self->name,"组长");returnhandler_handle(self,request);}GroupLeader*createGroupLeader(){GroupLeader*gl=(GroupLeader*)malloc(sizeof(GroupLeader));gl->base.handle=groupLeader_handle;gl->base.setNext=handler_setNext;gl->base.next=NULL;returngl;}// ========== 具体处理者:经理 ==========typedefstruct{Handler base;}Manager;intmanager_handle(Handler*self,Request*request){self->limit=5000;// 经理最多处理5000元strcpy(self->name,"经理");returnhandler_handle(self,request);}Manager*createManager(){Manager*m=(Manager*)malloc(sizeof(Manager));m->base.handle=manager_handle;m->base.setNext=handler_setNext;m->base.next=NULL;returnm;}// ========== 具体处理者:总经理 ==========typedefstruct{Handler base;}GeneralManager;intgeneralManager_handle(Handler*self,Request*request){self->limit=50000;// 总经理最多处理50000元strcpy(self->name,"总经理");returnhandler_handle(self,request);}GeneralManager*createGeneralManager(){GeneralManager*gm=(GeneralManager*)malloc(sizeof(GeneralManager));gm->base.handle=generalManager_handle;gm->base.setNext=handler_setNext;gm->base.next=NULL;returngm;}intmain(){printf("=== 责任链模式演示 ===\n\n");// 创建处理者链GroupLeader*leader=createGroupLeader();Manager*manager=createManager();GeneralManager*gm=createGeneralManager();// 设置责任链:组长 -> 经理 -> 总经理leader->base.setNext(&leader->base,(Handler*)manager);manager->base.setNext((Handler*)manager,(Handler*)gm);// 创建不同的请求printf("--- 请求1: 500元 ---\n");Request*req1=createRequest(500,"差旅费");leader->base.handle((Handler*)leader,req1);printf("\n--- 请求2: 3000元 ---\n");Request*req2=createRequest(3000,"设备采购");leader->base.handle((Handler*)leader,req2);printf("\n--- 请求3: 20000元 ---\n");Request*req3=createRequest(20000,"项目投资");leader->base.handle((Handler*)leader,req3);printf("\n--- 请求4: 100000元(超出所有处理者权限) ---\n");Request*req4=createRequest(100000,"大额投资");leader->base.handle((Handler*)leader,req4);// 释放内存free(req1);free(req2);free(req3);free(req4);free(leader);free(manager);free(gm);return0;}编译运行:
gcc chain_of_responsibility.c -o chain_of_responsibility ./chain_of_responsibility2. 命令模式(Command Pattern)
通俗解释:将请求封装成对象,从而可以用不同的请求对客户进行参数化。就像遥控器,每个按钮都是一个命令对象。
生活例子:
- 遥控器:每个按钮是一个命令,可以控制电视
- 菜单:每个菜单项是一个命令
- 撤销/重做:命令可以保存,支持撤销和重做
适用场景:
- 需要将请求参数化
- 需要支持撤销/重做
- 需要记录请求日志
C语言实现:
#include<stdio.h>#include<stdlib.h>#include<string.h>// ========== 接收者:电视 ==========// 这是实际执行操作的对象typedefstruct{intvolume;// 音量intchannel;// 频道intisOn;// 是否开机}TV;TV*createTV(){TV*tv=(TV*)malloc(sizeof(TV));tv->volume=50;tv->channel=1;tv->isOn=0;returntv;}voidtv_turnOn(TV*tv){tv->isOn=1;printf("电视已开机\n");}voidtv_turnOff(TV*tv){tv->isOn=0;printf("电视已关机\n");}voidtv_setVolume(TV*tv,intvolume){tv->volume=volume;printf("设置音量为: %d\n",volume);}voidtv_setChannel(TV*tv,intchannel){tv->channel=channel;printf("设置频道为: %d\n",channel);}voidtv_showStatus(TV*tv){printf("=== 电视状态 ===\n");printf("状态: %s\n",tv->isOn?"开机":"关机");printf("音量: %d\n",tv->volume);printf("频道: %d\n",tv->channel);printf("==============\n");}// ========== 命令接口 ==========typedefstruct{void(*execute)(void*self);// 执行命令void(*undo)(void*self);// 撤销命令chardescription[100];// 命令描述}Command;// ========== 具体命令:开机命令 ==========typedefstruct{Command base;TV*tv;intpreviousState;// 保存之前的状态,用于撤销}TurnOnCommand;voidturnOnCommand_execute(void*self){TurnOnCommand*cmd=(TurnOnCommand*)self;cmd->previousState=cmd->tv->isOn;tv_turnOn(cmd->tv);}voidturnOnCommand_undo(void*self){TurnOnCommand*cmd=(TurnOnCommand*)self;if(!cmd->previousState){tv_turnOff(cmd->tv);}}TurnOnCommand*createTurnOnCommand(TV*tv){TurnOnCommand*cmd=(TurnOnCommand*)malloc(sizeof(TurnOnCommand));cmd->base.execute=turnOnCommand_execute;cmd->base.undo=turnOnCommand_undo;strcpy(cmd->base.description,"开机");cmd->tv=tv;returncmd;}// ========== 具体命令:关机命令 ==========typedefstruct{Command base;TV*tv;intpreviousState;}TurnOffCommand;voidturnOffCommand_execute(void*self){TurnOffCommand*cmd=(TurnOffCommand*)self;cmd->previousState=cmd->tv->isOn;tv_turnOff(cmd->tv);}voidturnOffCommand_undo(void*self){TurnOffCommand*cmd=(TurnOffCommand*)self;if(cmd->previousState){tv_turnOn(cmd->tv);}}TurnOffCommand*createTurnOffCommand(TV*tv){TurnOffCommand*cmd=(TurnOffCommand*)malloc(sizeof(TurnOffCommand));cmd->base.execute=turnOffCommand_execute;cmd->base.undo=turnOffCommand_undo;strcpy(cmd->base.description,"关机");cmd->tv=tv;returncmd;}// ========== 具体命令:设置音量命令 ==========typedefstruct{Command base;TV*tv;intvolume;intpreviousVolume;}SetVolumeCommand;voidsetVolumeCommand_execute(void*self){SetVolumeCommand*cmd=(SetVolumeCommand*)self;cmd->previousVolume=cmd->tv->volume;tv_setVolume(cmd->tv,cmd->volume);}voidsetVolumeCommand_undo(void*self){SetVolumeCommand*cmd=(SetVolumeCommand*)self;tv_setVolume(cmd->tv,cmd->previousVolume);}SetVolumeCommand*createSetVolumeCommand(TV*tv,intvolume){SetVolumeCommand*cmd=(SetVolumeCommand*)malloc(sizeof(SetVolumeCommand));cmd->base.execute=setVolumeCommand_execute;cmd->base.undo=setVolumeCommand_undo;sprintf(cmd->base.description,"设置音量为%d",volume);cmd->tv=tv;cmd->volume=volume;returncmd;}// ========== 调用者:遥控器 ==========// 这是发送命令的对象typedefstruct{Command*command;// 当前命令Command*history[100];// 命令历史(用于撤销)inthistoryCount;}RemoteControl;RemoteControl*createRemoteControl(){RemoteControl*rc=(RemoteControl*)malloc(sizeof(RemoteControl));rc->command=NULL;rc->historyCount=0;returnrc;}voidremoteControl_setCommand(RemoteControl*rc,Command*cmd){rc->command=cmd;}voidremoteControl_pressButton(RemoteControl*rc){if(rc->command!=NULL){printf("执行命令: %s\n",rc->command->description);rc->command->execute(rc->command);// 保存到历史if(rc->historyCount<100){rc->history[rc->historyCount++]=rc->command;}}}voidremoteControl_undo(RemoteControl*rc){if(rc->historyCount>0){Command*lastCmd=rc->history[--rc->historyCount];printf("撤销命令: %s\n",lastCmd->description);lastCmd->undo(lastCmd);}else{printf("没有可撤销的命令\n");}}intmain(){printf("=== 命令模式演示 ===\n\n");// 创建接收者(电视)TV*tv=createTV();tv_showStatus(tv);// 创建命令TurnOnCommand*turnOn=createTurnOnCommand(tv);SetVolumeCommand*setVol=createSetVolumeCommand(tv,80);TurnOffCommand*turnOff=createTurnOffCommand(tv);// 创建调用者(遥控器)RemoteControl*remote=createRemoteControl();// 执行命令printf("\n--- 执行命令 ---\n");remoteControl_setCommand(remote,(Command*)turnOn);remoteControl_pressButton(remote);remoteControl_setCommand(remote,(Command*)setVol);remoteControl_pressButton(remote);tv_showStatus(tv);// 撤销命令printf("\n--- 撤销命令 ---\n");remoteControl_undo(remote);tv_showStatus(tv);remoteControl_undo(remote);tv_showStatus(tv);// 释放内存free(tv);free(turnOn);free(setVol);free(turnOff);free(remote);return0;}编译运行:
gcc command.c -ocommand./command3. 解释器模式(Interpreter Pattern)
通俗解释:定义语言的文法,并解释该语言中的句子。就像编译器,解释代码的含义。
生活例子:
- 计算器:解释数学表达式
- 正则表达式:解释匹配规则
- SQL解释器:解释SQL语句
适用场景:
- 需要解释特定语言
- 语法简单,性能要求不高
C语言实现:
#include<stdio.h>#include<stdlib.h>#include<string.h>#include<ctype.h>// ========== 表达式接口 ==========typedefstruct{int(*interpret)(void*self);// 解释函数}Expression;// ========== 终结符表达式:数字 ==========typedefstruct{Expression base;intvalue;}NumberExpression;intnumberExpression_interpret(void*self){NumberExpression*ne=(NumberExpression*)self;returnne->value;}NumberExpression*createNumberExpression(intvalue){NumberExpression*ne=(NumberExpression*)malloc(sizeof(NumberExpression));ne->base.interpret=numberExpression_interpret;ne->value=value;returnne;}// ========== 非终结符表达式:加法 ==========typedefstruct{Expression base;Expression*left;// 左表达式Expression*right;// 右表达式}AddExpression;intaddExpression_interpret(void*self){AddExpression*ae=(AddExpression*)self;intleftValue=ae->left->interpret(ae->left);intrightValue=ae->right->interpret(ae->right);returnleftValue+rightValue;}AddExpression*createAddExpression(Expression*left,Expression*right){AddExpression*ae=(AddExpression*)malloc(sizeof(AddExpression));ae->base.interpret=addExpression_interpret;ae->left=left;ae->right=right;returnae;}// ========== 非终结符表达式:减法 ==========typedefstruct{Expression base;Expression*left;Expression*right;}SubtractExpression;intsubtractExpression_interpret(void*self){SubtractExpression*se=(SubtractExpression*)self;intleftValue=se->left->interpret(se->left);intrightValue=se->right->interpret(se->right);returnleftValue-rightValue;}SubtractExpression*createSubtractExpression(Expression*left,Expression*right){SubtractExpression*se=(SubtractExpression*)malloc(sizeof(SubtractExpression));se->base.interpret=subtractExpression_interpret;se->left=left;se->right=right;returnse;}// ========== 非终结符表达式:乘法 ==========typedefstruct{Expression base;Expression*left;Expression*right;}MultiplyExpression;intmultiplyExpression_interpret(void*self){MultiplyExpression*me=(MultiplyExpression*)self;intleftValue=me->left->interpret(me->left);intrightValue=me->right->interpret(me->right);returnleftValue*rightValue;}MultiplyExpression*createMultiplyExpression(Expression*left,Expression*right){MultiplyExpression*me=(MultiplyExpression*)malloc(sizeof(MultiplyExpression));me->base.interpret=multiplyExpression_interpret;me->left=left;me->right=right;returnme;}// ========== 上下文:解析器 ==========// 简化版解析器,解析 "数字 运算符 数字" 格式Expression*parseExpression(constchar*expr){// 这里简化处理,实际应该用更复杂的解析器// 示例:解析 "5 + 3" 或 "10 - 2" 或 "4 * 2"intnum1=0,num2=0;charop='+';// 简单解析(实际应该用词法分析器和语法分析器)sscanf(expr,"%d %c %d",&num1,&op,&num2);Expression*left=(Expression*)createNumberExpression(num1);Expression*right=(Expression*)createNumberExpression(num2);switch(op){case'+':return(Expression*)createAddExpression(left,right);case'-':return(Expression*)createSubtractExpression(left,right);case'*':return(Expression*)createMultiplyExpression(left,right);default:returnleft;}}intmain(){printf("=== 解释器模式演示 ===\n\n");// 创建表达式:5 + 3Expression*left1=(Expression*)createNumberExpression(5);Expression*right1=(Expression*)createNumberExpression(3);Expression*expr1=(Expression*)createAddExpression(left1,right1);printf("表达式: 5 + 3\n");printf("结果: %d\n\n",expr1->interpret(expr1));// 创建表达式:10 - 2Expression*left2=(Expression*)createNumberExpression(10);Expression*right2=(Expression*)createNumberExpression(2);Expression*expr2=(Expression*)createSubtractExpression(left2,right2);printf("表达式: 10 - 2\n");printf("结果: %d\n\n",expr2->interpret(expr2));// 创建表达式:4 * 2Expression*left3=(Expression*)createNumberExpression(4);Expression*right3=(Expression*)createNumberExpression(2);Expression*expr3=(Expression*)createMultiplyExpression(left3,right3);printf("表达式: 4 * 2\n");printf("结果: %d\n\n",expr3->interpret(expr3));// 复杂表达式:(5 + 3) * 2Expression*complexLeft=(Expression*)createAddExpression((Expression*)createNumberExpression(5),(Expression*)createNumberExpression(3));Expression*complexRight=(Expression*)createNumberExpression(2);Expression*complexExpr=(Expression*)createMultiplyExpression(complexLeft,complexRight);printf("表达式: (5 + 3) * 2\n");printf("结果: %d\n\n",complexExpr->interpret(complexExpr));// 释放内存(简化版)free(left1);free(right1);free(expr1);free(left2);free(right2);free(expr2);free(left3);free(right3);free(expr3);free(complexLeft);free(complexRight);free(complexExpr);return0;}编译运行:
gcc interpreter.c -o interpreter ./interpreter4. 迭代器模式(Iterator Pattern)
通俗解释:提供一种方法顺序访问一个聚合对象中的各个元素,而不暴露其内部表示。就像遥控器,可以顺序切换电视频道。
生活例子:
- 遥控器:顺序切换频道
- 书签:顺序浏览网页
- 播放列表:顺序播放歌曲
适用场景:
- 需要遍历集合
- 需要统一遍历接口
C语言实现:
#include<stdio.h>#include<stdlib.h>#include<string.h>// ========== 迭代器接口 ==========typedefstruct{int(*hasNext)(void*self);// 是否有下一个元素void*(*next)(void*self);// 获取下一个元素void(*reset)(void*self);// 重置迭代器}Iterator;// ========== 聚合接口 ==========typedefstruct{Iterator*(*createIterator)(void*self);// 创建迭代器intsize;// 集合大小}Aggregate;// ========== 具体聚合:数组集合 ==========typedefstruct{Aggregate base;int*data;// 数据数组intcapacity;// 容量}ArrayCollection;// ========== 具体迭代器:数组迭代器 ==========typedefstruct{Iterator base;ArrayCollection*collection;// 关联的集合intcurrentIndex;// 当前索引}ArrayIterator;intarrayIterator_hasNext(void*self){ArrayIterator*it=(ArrayIterator*)self;returnit->currentIndex<it->collection->base.size;}void*arrayIterator_next(void*self){ArrayIterator*it=(ArrayIterator*)self;if(it->hasNext(it)){void*item=&it->collection->data[it->currentIndex++];returnitem;}returnNULL;}voidarrayIterator_reset(void*self){ArrayIterator*it=(ArrayIterator*)self;it->currentIndex=0;}Iterator*arrayIterator_create(ArrayCollection*collection){ArrayIterator*it=(ArrayIterator*)malloc(sizeof(ArrayIterator));it->base.hasNext=arrayIterator_hasNext;it->base.next=arrayIterator_next;it->base.reset=arrayIterator_reset;it->collection=collection;it->currentIndex=0;return(Iterator*)it;}Iterator*arrayCollection_createIterator(void*self){ArrayCollection*ac=(ArrayCollection*)self;returnarrayIterator_create(ac);}ArrayCollection*createArrayCollection(intcapacity){ArrayCollection*ac=(ArrayCollection*)malloc(sizeof(ArrayCollection));ac->data=(int*)malloc(sizeof(int)*capacity);ac->capacity=capacity;ac->base.size=0;ac->base.createIterator=arrayCollection_createIterator;returnac;}voidarrayCollection_add(ArrayCollection*ac,intvalue){if(ac->base.size<ac->capacity){ac->data[ac->base.size++]=value;}}// ========== 客户端代码 ==========voidtraverseCollection(Aggregate*aggregate){printf("遍历集合:\n");Iterator*it=aggregate->createIterator(aggregate);intindex=0;while(it->hasNext(it)){int*value=(int*)it->next(it);printf(" 元素[%d]: %d\n",index++,*value);}free(it);}intmain(){printf("=== 迭代器模式演示 ===\n\n");// 创建集合ArrayCollection*collection=createArrayCollection(10);// 添加元素arrayCollection_add(collection,10);arrayCollection_add(collection,20);arrayCollection_add(collection,30);arrayCollection_add(collection,40);arrayCollection_add(collection,50);printf("集合大小: %d\n\n",collection->base.size);// 使用迭代器遍历traverseCollection((Aggregate*)collection);// 手动使用迭代器printf("\n手动遍历:\n");Iterator*it=collection->base.createIterator(collection);while(it->hasNext(it)){int*value=(int*)it->next(it);printf("值: %d\n",*value);}// 重置迭代器printf("\n重置后再次遍历:\n");it->reset(it);while(it->hasNext(it)){int*value=(int*)it->next(it);printf("值: %d\n",*value);}// 释放内存free(it);free(collection->data);free(collection);return0;}编译运行:
gcc iterator.c -o iterator ./iterator5. 中介者模式(Mediator Pattern)
通俗解释:用一个中介对象来封装一系列对象的交互。就像聊天室,所有人通过聊天室交流,而不是直接互相联系。
生活例子:
- 聊天室:所有人通过聊天室交流
- 机场塔台:所有飞机通过塔台协调
- 股票交易所:所有交易通过交易所进行
适用场景:
- 对象之间有很多交互
- 需要解耦对象之间的直接依赖
C语言实现:
#include<stdio.h>#include<stdlib.h>#include<string.h>// ========== 中介者接口 ==========typedefstructMediator{void(*sendMessage)(structMediator*self,constchar*from,constchar*to,constchar*message);}Mediator;// ========== 同事接口 ==========typedefstructColleague{charname[50];Mediator*mediator;// 中介者引用void(*send)(structColleague*self,constchar*to,constchar*message);void(*receive)(structColleague*self,constchar*from,constchar*message);}Colleague;voidcolleague_send(Colleague*self,constchar*to,constchar*message){printf("%s 发送消息给 %s: %s\n",self->name,to,message);self->mediator->sendMessage(self->mediator,self->name,to,message);}voidcolleague_receive(Colleague*self,constchar*from,constchar*message){printf("%s 收到来自 %s 的消息: %s\n",self->name,from,message);}// ========== 具体中介者:聊天室 ==========typedefstruct{Mediator base;Colleague*colleagues[10];// 注册的同事intcount;}ChatRoom;voidchatRoom_sendMessage(Mediator*self,constchar*from,constchar*to,constchar*message){ChatRoom*cr=(ChatRoom*)self;// 查找接收者for(inti=0;i<cr->count;i++){if(strcmp(cr->colleagues[i]->name,to)==0){cr->colleagues[i]->receive(cr->colleagues[i],from,message);return;}}// 如果没找到接收者,可能是群发消息if(strcmp(to,"所有人")==0){printf("--- 群发消息 ---\n");for(inti=0;i<cr->count;i++){if(strcmp(cr->colleagues[i]->name,from)!=0){cr->colleagues[i]->receive(cr->colleagues[i],from,message);}}}else{printf("错误:找不到用户 %s\n",to);}}ChatRoom*createChatRoom(){ChatRoom*cr=(ChatRoom*)malloc(sizeof(ChatRoom));cr->base.sendMessage=chatRoom_sendMessage;cr->count=0;returncr;}voidchatRoom_register(ChatRoom*cr,Colleague*colleague){if(cr->count<10){cr->colleagues[cr->count++]=colleague;colleague->mediator=(Mediator*)cr;printf("%s 加入聊天室\n",colleague->name);}}// ========== 具体同事:用户 ==========typedefstruct{Colleague base;}User;User*createUser(constchar*name){User*user=(User*)malloc(sizeof(User));strcpy(user->base.name,name);user->base.send=colleague_send;user->base.receive=colleague_receive;user->base.mediator=NULL;returnuser;}intmain(){printf("=== 中介者模式演示 ===\n\n");// 创建中介者(聊天室)ChatRoom*chatRoom=createChatRoom();// 创建用户User*alice=createUser("Alice");User*bob=createUser("Bob");User*charlie=createUser("Charlie");// 注册到聊天室chatRoom_register(chatRoom,(Colleague*)alice);chatRoom_register(chatRoom,(Colleague*)bob);chatRoom_register(chatRoom,(Colleague*)charlie);printf("\n--- 开始聊天 ---\n");// 用户通过中介者(聊天室)发送消息alice->base.send((Colleague*)alice,"Bob","你好,Bob!");printf("\n");bob->base.send((Colleague*)bob,"Alice","你好,Alice!");printf("\n");charlie->base.send((Colleague*)charlie,"所有人","大家好!");// 释放内存free(alice);free(bob);free(charlie);free(chatRoom);return0;}编译运行:
gcc mediator.c -o mediator ./mediator6. 备忘录模式(Memento Pattern)
通俗解释:在不破坏封装性的前提下,捕获对象的内部状态,并在对象之外保存这个状态。就像游戏存档,可以保存和恢复游戏状态。
生活例子:
- 游戏存档:保存游戏状态,可以恢复
- 撤销功能:保存操作历史,可以撤销
- 数据库事务:保存事务状态,可以回滚
适用场景:
- 需要保存对象状态
- 需要支持撤销功能
C语言实现:
#include<stdio.h>#include<stdlib.h>#include<string.h>// ========== 备忘录:保存状态 ==========typedefstruct{intlevel;// 关卡intscore;// 分数inthealth;// 生命值charstate[100];// 状态描述}Memento;Memento*createMemento(intlevel,intscore,inthealth,constchar*state){Memento*m=(Memento*)malloc(sizeof(Memento));m->level=level;m->score=score;m->health=health;strcpy(m->state,state);returnm;}voidmemento_display(Memento*m){printf("=== 存档信息 ===\n");printf("关卡: %d\n",m->level);printf("分数: %d\n",m->score);printf("生命值: %d\n",m->health);printf("状态: %s\n",m->state);printf("==============\n");}// ========== 原发器:游戏角色 ==========// 需要保存状态的对象typedefstruct{intlevel;intscore;inthealth;charstate[100];Memento*(*save)(void*self);// 保存状态void(*restore)(void*self,Memento*m);// 恢复状态void(*play)(void*self);// 游戏操作void(*display)(void*self);// 显示状态}GameCharacter;Memento*gameCharacter_save(void*self){GameCharacter*gc=(GameCharacter*)self;sprintf(gc->state,"关卡%d-分数%d-生命%d",gc->level,gc->score,gc->health);returncreateMemento(gc->level,gc->score,gc->health,gc->state);}voidgameCharacter_restore(void*self,Memento*m){GameCharacter*gc=(GameCharacter*)self;gc->level=m->level;gc->score=m->score;gc->health=m->health;strcpy(gc->state,m->state);printf("恢复游戏状态\n");}voidgameCharacter_play(void*self){GameCharacter*gc=(GameCharacter*)self;gc->level++;gc->score+=100;gc->health-=10;sprintf(gc->state,"关卡%d-分数%d-生命%d",gc->level,gc->score,gc->health);printf("游戏进行中...\n");}voidgameCharacter_display(void*self){GameCharacter*gc=(GameCharacter*)self;printf("=== 当前游戏状态 ===\n");printf("关卡: %d\n",gc->level);printf("分数: %d\n",gc->score);printf("生命值: %d\n",gc->health);printf("状态: %s\n",gc->state);printf("==================\n");}GameCharacter*createGameCharacter(){GameCharacter*gc=(GameCharacter*)malloc(sizeof(GameCharacter));gc->level=1;gc->score=0;gc->health=100;strcpy(gc->state,"初始状态");gc->save=gameCharacter_save;gc->restore=gameCharacter_restore;gc->play=gameCharacter_play;gc->display=gameCharacter_display;returngc;}// ========== 管理者:存档管理器 ==========// 负责保存和管理备忘录typedefstruct{Memento*mementos[10];// 存档列表intcount;}Caretaker;Caretaker*createCaretaker(){Caretaker*ct=(Caretaker*)malloc(sizeof(Caretaker));ct->count=0;returnct;}voidcaretaker_save(Caretaker*ct,Memento*m){if(ct->count<10){ct->mementos[ct->count++]=m;printf("存档成功(存档%d)\n",ct->count);}else{printf("存档已满\n");}}Memento*caretaker_load(Caretaker*ct,intindex){if(index>=1&&index<=ct->count){printf("加载存档%d\n",index);returnct->mementos[index-1];}printf("存档不存在\n");returnNULL;}intmain(){printf("=== 备忘录模式演示 ===\n\n");// 创建游戏角色GameCharacter*character=createGameCharacter();character->display(character);// 创建存档管理器Caretaker*caretaker=createCaretaker();// 保存初始状态printf("\n--- 保存初始状态 ---\n");Memento*save1=character->save(character);caretaker_save(caretaker,save1);// 游戏进行printf("\n--- 游戏进行 ---\n");character->play(character);character->display(character);// 保存进度printf("\n--- 保存进度1 ---\n");Memento*save2=character->save(character);caretaker_save(caretaker,save2);// 继续游戏printf("\n--- 继续游戏 ---\n");character->play(character);character->display(character);// 恢复存档1printf("\n--- 恢复到存档1 ---\n");Memento*loaded=caretaker_load(caretaker,1);if(loaded){memento_display(loaded);character->restore(character,loaded);character->display(character);}// 释放内存(简化版)free(character);for(inti=0;i<caretaker->count;i++){free(caretaker->mementos[i]);}free(caretaker);return0;}编译运行:
gcc memento.c -o memento ./memento7. 观察者模式(Observer Pattern)
通俗解释:定义对象间一对多的依赖关系,当一个对象状态改变时,所有依赖它的对象都会收到通知。就像订阅报纸,报纸更新时,所有订阅者都会收到。
生活例子:
- 订阅报纸:报纸更新,订阅者收到
- 微信朋友圈:发朋友圈,好友收到通知
- 股票价格:价格变化,所有关注者收到通知
适用场景:
- 一个对象状态改变需要通知多个对象
- 需要解耦观察者和被观察者
C语言实现:
#include<stdio.h>#include<stdlib.h>#include<string.h>// ========== 观察者接口 ==========typedefstructObserver{charname[50];void(*update)(structObserver*self,constchar*message);// 更新函数}Observer;// ========== 主题接口 ==========typedefstructSubject{Observer*observers[10];// 观察者列表intobserverCount;// 观察者数量void(*attach)(structSubject*self,Observer*observer);// 添加观察者void(*detach)(structSubject*self,Observer*observer);// 移除观察者void(*notify)(structSubject*self,constchar*message);// 通知观察者}Subject;voidsubject_attach(Subject*self,Observer*observer){if(self->observerCount<10){self->observers[self->observerCount++]=observer;printf("%s 订阅了主题\n",observer->name);}}voidsubject_detach(Subject*self,Observer*observer){for(inti=0;i<self->observerCount;i++){if(self->observers[i]==observer){// 移除观察者for(intj=i;j<self->observerCount-1;j++){self->observers[j]=self->observers[j+1];}self->observerCount--;printf("%s 取消订阅\n",observer->name);return;}}}voidsubject_notify(Subject*self,constchar*message){printf("\n--- 通知所有观察者 ---\n");for(inti=0;i<self->observerCount;i++){self->observers[i]->update(self->observers[i],message);}}// ========== 具体主题:新闻发布者 ==========typedefstruct{Subject base;charnews[200];// 新闻内容}NewsPublisher;NewsPublisher*createNewsPublisher(){NewsPublisher*np=(NewsPublisher*)malloc(sizeof(NewsPublisher));np->base.attach=subject_attach;np->base.detach=subject_detach;np->base.notify=subject_notify;np->base.observerCount=0;strcpy(np->news,"");returnnp;}voidnewsPublisher_publish(NewsPublisher*np,constchar*news){strcpy(np->news,news);printf("发布新闻: %s\n",news);np->base.notify(&np->base,news);}// ========== 具体观察者:订阅者 ==========typedefstruct{Observer base;}NewsSubscriber;voidnewsSubscriber_update(Observer*self,constchar*message){printf("%s 收到新闻: %s\n",self->name,message);}NewsSubscriber*createNewsSubscriber(constchar*name){NewsSubscriber*ns=(NewsSubscriber*)malloc(sizeof(NewsSubscriber));strcpy(ns->base.name,name);ns->base.update=newsSubscriber_update;returnns;}intmain(){printf("=== 观察者模式演示 ===\n\n");// 创建主题(新闻发布者)NewsPublisher*publisher=createNewsPublisher();// 创建观察者(订阅者)NewsSubscriber*subscriber1=createNewsSubscriber("张三");NewsSubscriber*subscriber2=createNewsSubscriber("李四");NewsSubscriber*subscriber3=createNewsSubscriber("王五");// 订阅publisher->base.attach(&publisher->base,(Observer*)subscriber1);publisher->base.attach(&publisher->base,(Observer*)subscriber2);publisher->base.attach(&publisher->base,(Observer*)subscriber3);// 发布新闻printf("\n");newsPublisher_publish(publisher,"今天天气很好!");// 取消订阅printf("\n");publisher->base.detach(&publisher->base,(Observer*)subscriber2);// 再次发布新闻printf("\n");newsPublisher_publish(publisher,"明天要下雨了!");// 释放内存free(publisher);free(subscriber1);free(subscriber2);free(subscriber3);return0;}编译运行:
gcc observer.c -o observer ./observer8. 状态模式(State Pattern)
通俗解释:允许对象在内部状态改变时改变它的行为。就像自动售货机,不同状态(有货/无货)有不同的行为。
生活例子:
- 自动售货机:有货/无货状态,行为不同
- 交通灯:红灯/绿灯/黄灯状态
- 游戏角色:正常/受伤/死亡状态
适用场景:
- 对象行为依赖于状态
- 需要根据状态改变行为
C语言实现:
#include<stdio.h>#include<stdlib.h>#include<string.h>// ========== 状态接口 ==========typedefstructState{void(*handle)(void*self);// 处理函数charname[50];}State;// ========== 上下文:自动售货机 ==========typedefstruct{State*currentState;// 当前状态intitemCount;// 商品数量void(*request)(void*self);// 请求操作void(*setState)(void*self,State*state);// 设置状态}VendingMachine;voidvendingMachine_request(void*self){VendingMachine*vm=(VendingMachine*)self;printf("当前状态: %s\n",vm->currentState->name);vm->currentState->handle(vm->currentState);}voidvendingMachine_setState(void*self,State*state){VendingMachine*vm=(VendingMachine*)self;vm->currentState=state;printf("状态切换为: %s\n",state->name);}VendingMachine*createVendingMachine(){VendingMachine*vm=(VendingMachine*)malloc(sizeof(VendingMachine));vm->itemCount=0;vm->request=vendingMachine_request;vm->setState=vendingMachine_setState;returnvm;}// ========== 具体状态:有货状态 ==========typedefstruct{State base;VendingMachine*machine;}HasItemState;voidhasItemState_handle(void*self){HasItemState*state=(HasItemState*)self;printf("有货状态:可以购买\n");state->machine->itemCount--;printf("售出一件商品,剩余: %d\n",state->machine->itemCount);// 如果商品售完,切换到无货状态if(state->machine->itemCount==0){// 这里简化处理,实际应该通过状态管理器切换printf("商品售完,切换到无货状态\n");}}HasItemState*createHasItemState(VendingMachine*machine){HasItemState*state=(HasItemState*)malloc(sizeof(HasItemState));strcpy(state->base.name,"有货");state->base.handle=hasItemState_handle;state->machine=machine;returnstate;}// ========== 具体状态:无货状态 ==========typedefstruct{State base;VendingMachine*machine;}NoItemState;voidnoItemState_handle(void*self){NoItemState*state=(NoItemState*)self;printf("无货状态:无法购买,请补货\n");}NoItemState*createNoItemState(VendingMachine*machine){NoItemState*state=(NoItemState*)malloc(sizeof(NoItemState));strcpy(state->base.name,"无货");state->base.handle=noItemState_handle;state->machine=machine;returnstate;}intmain(){printf("=== 状态模式演示 ===\n\n");// 创建自动售货机VendingMachine*machine=createVendingMachine();machine->itemCount=3;// 初始有3件商品// 创建状态HasItemState*hasItem=createHasItemState(machine);NoItemState*noItem=createNoItemState(machine);// 设置初始状态machine->setState(machine,(State*)hasItem);// 购买商品printf("\n--- 购买商品1 ---\n");machine->request(machine);printf("\n--- 购买商品2 ---\n");machine->request(machine);printf("\n--- 购买商品3 ---\n");machine->request(machine);// 切换到无货状态printf("\n--- 商品售完 ---\n");machine->setState(machine,(State*)noItem);// 尝试购买(无货)printf("\n--- 尝试购买(无货) ---\n");machine->request(machine);// 释放内存free(machine);free(hasItem);free(noItem);return0;}编译运行:
gcc state.c -o state ./state9. 策略模式(Strategy Pattern)
通俗解释:定义一系列算法,把它们封装起来,并且使它们可以互换。就像支付方式,可以用支付宝、微信、信用卡等不同策略。
生活例子:
- 支付方式:支付宝、微信、信用卡等不同策略
- 排序算法:快速排序、冒泡排序、归并排序等
- 导航方式:步行、开车、公交等不同路线策略
适用场景:
- 需要在运行时选择算法
- 有多个相似的类,只是行为不同
C语言实现:
#include<stdio.h>#include<stdlib.h>#include<string.h>// ========== 策略接口:支付策略 ==========typedefstruct{void(*pay)(void*self,doubleamount);// 支付函数charname[50];}PaymentStrategy;// ========== 具体策略:支付宝支付 ==========typedefstruct{PaymentStrategy base;}AlipayStrategy;voidalipayStrategy_pay(void*self,doubleamount){printf("使用支付宝支付: %.2f 元\n",amount);printf("跳转到支付宝支付页面...\n");printf("支付成功!\n");}AlipayStrategy*createAlipayStrategy(){AlipayStrategy*strategy=(AlipayStrategy*)malloc(sizeof(AlipayStrategy));strcpy(strategy->base.name,"支付宝");strategy->base.pay=alipayStrategy_pay;returnstrategy;}// ========== 具体策略:微信支付 ==========typedefstruct{PaymentStrategy base;}WeChatStrategy;voidweChatStrategy_pay(void*self,doubleamount){printf("使用微信支付: %.2f 元\n",amount);printf("打开微信支付...\n");printf("支付成功!\n");}WeChatStrategy*createWeChatStrategy(){WeChatStrategy*strategy=(WeChatStrategy*)malloc(sizeof(WeChatStrategy));strcpy(strategy->base.name,"微信");strategy->base.pay=weChatStrategy_pay;returnstrategy;}// ========== 具体策略:信用卡支付 ==========typedefstruct{PaymentStrategy base;}CreditCardStrategy;voidcreditCardStrategy_pay(void*self,doubleamount){printf("使用信用卡支付: %.2f 元\n",amount);printf("输入信用卡信息...\n");printf("支付成功!\n");}CreditCardStrategy*createCreditCardStrategy(){CreditCardStrategy*strategy=(CreditCardStrategy*)malloc(sizeof(CreditCardStrategy));strcpy(strategy->base.name,"信用卡");strategy->base.pay=creditCardStrategy_pay;returnstrategy;}// ========== 上下文:购物车 ==========typedefstruct{PaymentStrategy*strategy;// 当前支付策略doubletotal;// 总金额void(*setPaymentStrategy)(void*self,PaymentStrategy*strategy);// 设置支付策略void(*checkout)(void*self);// 结账void(*addItem)(void*self,doubleprice);// 添加商品}ShoppingCart;voidshoppingCart_setPaymentStrategy(void*self,PaymentStrategy*strategy){ShoppingCart*cart=(ShoppingCart*)self;cart->strategy=strategy;printf("设置支付方式为: %s\n",strategy->name);}voidshoppingCart_checkout(void*self){ShoppingCart*cart=(ShoppingCart*)self;if(cart->strategy==NULL){printf("错误:未设置支付方式\n");return;}printf("\n=== 结账 ===\n");printf("总金额: %.2f 元\n",cart->total);cart->strategy->pay(cart->strategy,cart->total);printf("===========\n\n");}voidshoppingCart_addItem(void*self,doubleprice){ShoppingCart*cart=(ShoppingCart*)self;cart->total+=price;printf("添加商品,价格: %.2f 元,总计: %.2f 元\n",price,cart->total);}ShoppingCart*createShoppingCart(){ShoppingCart*cart=(ShoppingCart*)malloc(sizeof(ShoppingCart));cart->strategy=NULL;cart->total=0.0;cart->setPaymentStrategy=shoppingCart_setPaymentStrategy;cart->checkout=shoppingCart_checkout;cart->addItem=shoppingCart_addItem;returncart;}intmain(){printf("=== 策略模式演示 ===\n\n");// 创建购物车ShoppingCart*cart=createShoppingCart();// 添加商品cart->addItem(cart,100.0);cart->addItem(cart,50.0);cart->addItem(cart,30.0);// 使用不同的支付策略printf("\n--- 使用支付宝支付 ---\n");AlipayStrategy*alipay=createAlipayStrategy();cart->setPaymentStrategy(cart,(PaymentStrategy*)alipay);cart->checkout(cart);// 重置购物车cart->total=180.0;printf("--- 使用微信支付 ---\n");WeChatStrategy*wechat=createWeChatStrategy();cart->setPaymentStrategy(cart,(PaymentStrategy*)wechat);cart->checkout(cart);// 重置购物车cart->total=180.0;printf("--- 使用信用卡支付 ---\n");CreditCardStrategy*credit=createCreditCardStrategy();cart->setPaymentStrategy(cart,(PaymentStrategy*)credit);cart->checkout(cart);// 释放内存free(cart);free(alipay);free(wechat);free(credit);return0;}编译运行:
gcc strategy.c -o strategy ./strategy10. 模板方法模式(Template Method Pattern)
通俗解释:定义一个操作中算法的骨架,而将一些步骤延迟到子类中。就像做菜,步骤固定(洗菜、切菜、炒菜),但具体做法可以不同。
生活例子:
- 做菜:步骤固定,但具体做法不同
- 考试:流程固定(发卷、答题、收卷),但题目不同
- 银行开户:流程固定,但不同银行细节不同
适用场景:
- 有多个类有相似的算法结构
- 需要控制算法的流程
C语言实现:
#include<stdio.h>#include<stdlib.h>#include<string.h>// ========== 抽象类:饮料制作模板 ==========typedefstruct{void(*brew)(void*self);// 冲泡(抽象方法)void(*addCondiments)(void*self);// 添加调料(抽象方法)void(*makeBeverage)(void*self);// 制作饮料(模板方法)}BeverageTemplate;// 模板方法:定义算法骨架voidbeverageTemplate_makeBeverage(void*self){BeverageTemplate*bt=(BeverageTemplate*)self;printf("=== 开始制作饮料 ===\n");printf("步骤1: 烧水\n");printf("步骤2: ");bt->brew(bt);// 调用具体实现printf("步骤3: 倒入杯子\n");printf("步骤4: ");bt->addCondiments(bt);// 调用具体实现printf("步骤5: 完成\n");printf("==================\n\n");}// ========== 具体类:咖啡 ==========typedefstruct{BeverageTemplate base;}Coffee;voidcoffee_brew(void*self){printf("冲泡咖啡\n");}voidcoffee_addCondiments(void*self){printf("添加糖和牛奶\n");}Coffee*createCoffee(){Coffee*coffee=(Coffee*)malloc(sizeof(Coffee));coffee->base.brew=coffee_brew;coffee->base.addCondiments=coffee_addCondiments;coffee->base.makeBeverage=beverageTemplate_makeBeverage;returncoffee;}// ========== 具体类:茶 ==========typedefstruct{BeverageTemplate base;}Tea;voidtea_brew(void*self){printf("冲泡茶叶\n");}voidtea_addCondiments(void*self){printf("添加柠檬\n");}Tea*createTea(){Tea*tea=(Tea*)malloc(sizeof(Tea));tea->base.brew=tea_brew;tea->base.addCondiments=tea_addCondiments;tea->base.makeBeverage=beverageTemplate_makeBeverage;returntea;}// ========== 具体类:纯咖啡(不添加调料) ==========typedefstruct{BeverageTemplate base;}BlackCoffee;voidblackCoffee_brew(void*self){printf("冲泡咖啡\n");}voidblackCoffee_addCondiments(void*self){printf("不添加任何调料(纯咖啡)\n");}BlackCoffee*createBlackCoffee(){BlackCoffee*bc=(BlackCoffee*)malloc(sizeof(BlackCoffee));bc->base.brew=blackCoffee_brew;bc->base.addCondiments=blackCoffee_addCondiments;bc->base.makeBeverage=beverageTemplate_makeBeverage;returnbc;}intmain(){printf("=== 模板方法模式演示 ===\n\n");// 制作咖啡Coffee*coffee=createCoffee();coffee->base.makeBeverage(&coffee->base);// 制作茶Tea*tea=createTea();tea->base.makeBeverage(&tea->base);// 制作纯咖啡BlackCoffee*blackCoffee=createBlackCoffee();blackCoffee->base.makeBeverage(&blackCoffee->base);// 释放内存free(coffee);free(tea);free(blackCoffee);return0;}编译运行:
gcc template_method.c -o template_method ./template_method11. 访问者模式(Visitor Pattern)
通俗解释:表示一个作用于某对象结构中的各元素的操作,可以在不改变各元素类的前提下定义作用于这些元素的新操作。就像医生访问病人,对不同病人做不同检查。
生活例子:
- 医生访问病人:对不同病人做不同检查
- 税务审计:对不同公司做不同审计
- 编译器:对不同语法节点做不同处理
适用场景:
- 需要对对象结构中的元素执行不同操作
- 需要在不改变元素类的情况下添加新操作
C语言实现:
#include<stdio.h>#include<stdlib.h>#include<string.h>// ========== 访问者接口 ==========typedefstructVisitor{void(*visitElementA)(structVisitor*self,void*element);// 访问元素Avoid(*visitElementB)(structVisitor*self,void*element);// 访问元素B}Visitor;// ========== 元素接口 ==========typedefstructElement{void(*accept)(void*self,Visitor*visitor);// 接受访问者charname[50];}Element;// ========== 具体元素A ==========typedefstruct{Element base;intvalueA;}ConcreteElementA;voidelementA_accept(void*self,Visitor*visitor){ConcreteElementA*elem=(ConcreteElementA*)self;printf("%s 接受访问\n",elem->base.name);visitor->visitElementA(visitor,elem);}ConcreteElementA*createElementA(constchar*name,intvalue){ConcreteElementA*elem=(ConcreteElementA*)malloc(sizeof(ConcreteElementA));strcpy(elem->base.name,name);elem->base.accept=elementA_accept;elem->valueA=value;returnelem;}// ========== 具体元素B ==========typedefstruct{Element base;charvalueB[50];}ConcreteElementB;voidelementB_accept(void*self,Visitor*visitor){ConcreteElementB*elem=(ConcreteElementB*)self;printf("%s 接受访问\n",elem->base.name);visitor->visitElementB(visitor,elem);}ConcreteElementB*createElementB(constchar*name,constchar*value){ConcreteElementB*elem=(ConcreteElementB*)malloc(sizeof(ConcreteElementB));strcpy(elem->base.name,name);elem->base.accept=elementB_accept;strcpy(elem->valueB,value);returnelem;}// ========== 具体访问者:操作1 ==========typedefstruct{Visitor base;}ConcreteVisitor1;voidvisitor1_visitElementA(Visitor*self,void*element){ConcreteElementA*elem=(ConcreteElementA*)element;printf("访问者1 访问元素A: %s,执行操作1,值: %d\n",elem->base.name,elem->valueA);}voidvisitor1_visitElementB(Visitor*self,void*element){ConcreteElementB*elem=(ConcreteElementB*)element;printf("访问者1 访问元素B: %s,执行操作1,值: %s\n",elem->base.name,elem->valueB);}ConcreteVisitor1*createVisitor1(){ConcreteVisitor1*v=(ConcreteVisitor1*)malloc(sizeof(ConcreteVisitor1));v->base.visitElementA=visitor1_visitElementA;v->base.visitElementB=visitor1_visitElementB;returnv;}// ========== 具体访问者:操作2 ==========typedefstruct{Visitor base;}ConcreteVisitor2;voidvisitor2_visitElementA(Visitor*self,void*element){ConcreteElementA*elem=(ConcreteElementA*)element;printf("访问者2 访问元素A: %s,执行操作2,值: %d\n",elem->base.name,elem->valueA);}voidvisitor2_visitElementB(Visitor*self,void*element){ConcreteElementB*elem=(ConcreteElementB*)element;printf("访问者2 访问元素B: %s,执行操作2,值: %s\n",elem->base.name,elem->valueB);}ConcreteVisitor2*createVisitor2(){ConcreteVisitor2*v=(ConcreteVisitor2*)malloc(sizeof(ConcreteVisitor2));v->base.visitElementA=visitor2_visitElementA;v->base.visitElementB=visitor2_visitElementB;returnv;}// ========== 对象结构 ==========typedefstruct{Element*elements[10];intcount;void(*add)(void*self,Element*element);void(*accept)(void*self,Visitor*visitor);}ObjectStructure;voidobjectStructure_add(void*self,Element*element){ObjectStructure*os=(ObjectStructure*)self;if(os->count<10){os->elements[os->count++]=element;}}voidobjectStructure_accept(void*self,Visitor*visitor){ObjectStructure*os=(ObjectStructure*)self;printf("\n=== 访问对象结构 ===\n");for(inti=0;i<os->count;i++){os->elements[i]->accept(os->elements[i],visitor);}printf("==================\n\n");}ObjectStructure*createObjectStructure(){ObjectStructure*os=(ObjectStructure*)malloc(sizeof(ObjectStructure));os->count=0;os->add=objectStructure_add;os->accept=objectStructure_accept;returnos;}intmain(){printf("=== 访问者模式演示 ===\n\n");// 创建元素ConcreteElementA*elemA=createElementA("元素A",100);ConcreteElementB*elemB=createElementB("元素B","Hello");// 创建对象结构ObjectStructure*structure=createObjectStructure();structure->add(structure,(Element*)elemA);structure->add(structure,(Element*)elemB);// 使用访问者1访问ConcreteVisitor1*visitor1=createVisitor1();structure->accept(structure,(Visitor*)visitor1);// 使用访问者2访问ConcreteVisitor2*visitor2=createVisitor2();structure->accept(structure,(Visitor*)visitor2);// 释放内存free(elemA);free(elemB);free(structure);free(visitor1);free(visitor2);return0;}编译运行:
gcc visitor.c -o visitor ./visitor总结:行为型模式
行为型模式帮助我们管理对象之间的通信和职责:
- 责任链模式:将请求沿着处理者链传递
- 命令模式:将请求封装成对象
- 解释器模式:定义语言的文法并解释
- 迭代器模式:顺序访问集合元素
- 中介者模式:封装对象间的交互
- 备忘录模式:保存和恢复对象状态
- 观察者模式:一对多的依赖关系
- 状态模式:根据状态改变行为
- 策略模式:封装可互换的算法
- 模板方法模式:定义算法骨架
- 访问者模式:在不改变元素类的前提下定义新操作
每种模式都解决了不同的行为问题,让代码更灵活、更易维护。
完整总结:23种设计模式
创建型模式(5个)
- 单例模式
- 工厂方法模式
- 抽象工厂模式
- 建造者模式
- 原型模式
结构型模式(7个)
- 适配器模式
- 桥接模式
- 组合模式
- 装饰器模式
- 外观模式
- 享元模式
- 代理模式
行为型模式(11个)
- 责任链模式
- 命令模式
- 解释器模式
- 迭代器模式
- 中介者模式
- 备忘录模式
- 观察者模式
- 状态模式
- 策略模式
- 模板方法模式
- 访问者模式
所有模式都遵循7大设计原则,帮助我们写出更好的代码!