c++注意点(11)----设计模式(工厂方法)
创建型模式
工厂方法模式是一种创建型设计模式, 其在父类中提供一个创建对象的方法, 允许子类决定实例化对象的类型。
为什么需要工厂方法模式?
看一个 “没有工厂模式” 的痛点场景:
假设你在开发一个游戏,最初只有 “战士” 一种角色,代码可能这样写:
// 早期代码:直接在客户端创建对象void startGame() { // 直接new具体角色 Warrior* warrior = new Warrior(); warrior->attack(); // ...}
但随着游戏迭代,需要添加 “法师” 角色,你不得不修改客户端代码:
// 迭代后:客户端代码被迫修改void startGame(std::string roleType) { Character* character; // 客户端需要知道所有具体角色的类型 if (roleType == \"warrior\") { character = new Warrior(); } else if (roleType == \"mage\") { // 新增逻辑 character = new Mage(); } character->attack(); // ...}
继续迭代添加 “弓箭手”“刺客” 时,客户端代码会被反复修改,最终变得臃肿且脆弱。
工厂方法优点
1.解耦对象创建与使用
2.符合开闭原则
新增产品时,只需添加对应的具体产品类(如Assassin)和具体工厂类(如AssassinFactory),无需修改现有工厂和客户端代码。例如要增加 “刺客” 角色,原有的战士、法师工厂代码完全不用动。
3.单一职责原则
每个具体工厂只负责创建一种产品(如WarriorFactory
只创建战士),职责清晰,避免了一个类承担过多创建逻辑。
4.支持多态创建
客户端可以通过相同的接口(抽象工厂)创建不同类型的产品。
5.便于扩展和测试
示例
#include #include #include // 产品接口:游戏角色class Character {public: virtual ~Character() = default; virtual void attack() const = 0; // 攻击方法 virtual void defend() const = 0; // 防御方法 virtual std::string getName() const = 0; // 获取角色名称};// 具体产品1:战士(近战高防御)class Warrior : public Character {public: void attack() const override { std::cout << \"战士挥舞大剑,进行猛烈劈砍!\" << std::endl; } void defend() const override { std::cout << \"战士举起盾牌,形成坚固防御!\" << std::endl; } std::string getName() const override { return \"钢铁战士\"; }};// 具体产品2:法师(远程魔法攻击)class Mage : public Character {public: void attack() const override { std::cout << \"法师吟唱咒语,释放火球术!\" << std::endl; } void defend() const override { std::cout << \"法师召唤魔法屏障,抵御伤害!\" << std::endl; } std::string getName() const override { return \"元素法师\"; }};// 具体产品3:弓箭手(远程物理攻击)class Archer : public Character {public: void attack() const override { std::cout << \"弓箭手拉满长弓,射出精准箭矢!\" << std::endl; } void defend() const override { std::cout << \"弓箭手快速后跳,闪避攻击!\" << std::endl; } std::string getName() const override { return \"精灵弓箭手\"; }};// 抽象工厂:角色创建工厂class CharacterFactory {public: virtual ~CharacterFactory() = default; virtual std::unique_ptr createCharacter() = 0; // 工厂方法:创建角色};// 具体工厂1:战士工厂class WarriorFactory : public CharacterFactory {public: std::unique_ptr createCharacter() override { std::cout << \"=== 战士工厂创建角色 ===\" << std::endl; return std::make_unique(); // 创建战士 }};// 具体工厂2:法师工厂class MageFactory : public CharacterFactory {public: std::unique_ptr createCharacter() override { std::cout << \"=== 法师工厂创建角色 ===\" << std::endl; return std::make_unique(); // 创建法师 }};// 具体工厂3:弓箭手工厂class ArcherFactory : public CharacterFactory {public: std::unique_ptr createCharacter() override { std::cout << \"=== 弓箭手工厂创建角色 ===\" << std::endl; return std::make_unique(); // 创建弓箭手 }};// 客户端:游戏角色选择系统class GameSystem {public: // 根据选择的工厂创建角色并执行操作 static void playWithCharacter(CharacterFactory& factory) { auto character = factory.createCharacter(); // 通过工厂获取角色 std::cout << \"创建了角色:\" <getName() <attack(); character->defend(); std::cout << std::endl; }};int main() { // 玩家选择战士 WarriorFactory warriorFactory; GameSystem::playWithCharacter(warriorFactory); // 玩家选择法师 MageFactory mageFactory; GameSystem::playWithCharacter(mageFactory); // 玩家选择弓箭手 ArcherFactory archerFactory; GameSystem::playWithCharacter(archerFactory); // 如需添加新角色(如刺客),只需新增: // 1. Assassin类(实现Character接口) // 2. AssassinFactory类(实现CharacterFactory接口) // 无需修改现有代码,符合开闭原则 return 0;}
c语言的工厂方法模式
我们在用keil5开发单片机程序时候,可以也学着这种方法去开发。这样结构清晰。具体就是将共有的部分抽离出来,做结构体。功能的实现封装函数指针,放入结构体中。这样子对于多模块的使用,以及后续拓展都有很好的便捷性。
给出示例
#include #include #include // -------------------------- 外设抽象产品 --------------------------// 外设抽象接口(相当于抽象类)typedef struct Peripheral { void (*enable)(struct Peripheral*); // 使能设备 void (*disable)(struct Peripheral*); // 禁用设备 void (*set_param)(struct Peripheral*, int param, int value); // 设置参数 void (*destroy)(struct Peripheral*); // 销毁资源 const char* name; // 设备名称 // 可以添加通用属性,如设备地址、状态等 int address; int status; // 0: 禁用, 1: 使能} Peripheral;// -------------------------- 具体产品实现(电机) --------------------------// 电机特有参数定义#define MOTOR_PARAM_SPEED 1 // 速度参数#define MOTOR_PARAM_DIRECTION 2 // 方向参数// 电机使能static void motor_enable(Peripheral* dev) { dev->status = 1; printf(\"[%s] 已使能 (地址: 0x%02X) - 开始运转\\n\", dev->name, dev->address);}// 电机禁用static void motor_disable(Peripheral* dev) { dev->status = 0; printf(\"[%s] 已禁用 (地址: 0x%02X) - 停止运转\\n\", dev->name, dev->address);}// 电机参数设置(速度0-100,方向0-1)static void motor_set_param(Peripheral* dev, int param, int value) { if (dev->status != 1) { printf(\"[%s] 未使能,无法设置参数\\n\", dev->name); return; } switch(param) { case MOTOR_PARAM_SPEED: printf(\"[%s] 设置速度: %d%%\\n\", dev->name, value); break; case MOTOR_PARAM_DIRECTION: printf(\"[%s] 设置方向: %s\\n\", dev->name, value ? \"正向\" : \"反向\"); break; default: printf(\"[%s] 未知参数: %d\\n\", dev->name, param); }}// 电机资源销毁static void motor_destroy(Peripheral* dev) { printf(\"[%s] 销毁资源 (地址: 0x%02X)\\n\", dev->name, dev->address); free(dev);}// 创建电机设备Peripheral* create_motor(int address) { Peripheral* motor = (Peripheral*)malloc(sizeof(Peripheral)); if (!motor) return NULL; motor->name = \"直流电机\"; motor->address = address; motor->status = 0; // 初始禁用状态 motor->enable = motor_enable; motor->disable = motor_disable; motor->set_param = motor_set_param; motor->destroy = motor_destroy; return motor;}// -------------------------- 具体产品实现(显示屏) --------------------------// 显示屏特有参数定义#define DISPLAY_PARAM_BRIGHTNESS 1 // 亮度参数#define DISPLAY_PARAM_CONTRAST 2 // 对比度参数// 显示屏使能static void display_enable(Peripheral* dev) { dev->status = 1; printf(\"[%s] 已使能 (地址: 0x%02X) - 屏幕点亮\\n\", dev->name, dev->address);}// 显示屏禁用static void display_disable(Peripheral* dev) { dev->status = 0; printf(\"[%s] 已禁用 (地址: 0x%02X) - 屏幕关闭\\n\", dev->name, dev->address);}// 显示屏参数设置(亮度0-100,对比度0-100)static void display_set_param(Peripheral* dev, int param, int value) { if (dev->status != 1) { printf(\"[%s] 未使能,无法设置参数\\n\", dev->name); return; } switch(param) { case DISPLAY_PARAM_BRIGHTNESS: printf(\"[%s] 设置亮度: %d%%\\n\", dev->name, value); break; case DISPLAY_PARAM_CONTRAST: printf(\"[%s] 设置对比度: %d%%\\n\", dev->name, value); break; default: printf(\"[%s] 未知参数: %d\\n\", dev->name, param); }}// 显示屏资源销毁static void display_destroy(Peripheral* dev) { printf(\"[%s] 销毁资源 (地址: 0x%02X)\\n\", dev->name, dev->address); free(dev);}// 创建显示屏设备Peripheral* create_display(int address) { Peripheral* display = (Peripheral*)malloc(sizeof(Peripheral)); if (!display) return NULL; display->name = \"OLED显示屏\"; display->address = address; display->status = 0; // 初始禁用状态 display->enable = display_enable; display->disable = display_disable; display->set_param = display_set_param; display->destroy = display_destroy; return display;}// -------------------------- 具体产品实现(继电器) --------------------------// 继电器特有参数定义#define RELAY_PARAM_DELAY 1 // 延迟参数(毫秒)// 继电器使能static void relay_enable(Peripheral* dev) { dev->status = 1; printf(\"[%s] 已使能 (地址: 0x%02X) - 开关闭合\\n\", dev->name, dev->address);}// 继电器禁用static void relay_disable(Peripheral* dev) { dev->status = 0; printf(\"[%s] 已禁用 (地址: 0x%02X) - 开关断开\\n\", dev->name, dev->address);}// 继电器参数设置(延迟时间)static void relay_set_param(Peripheral* dev, int param, int value) { if (dev->status != 1) { printf(\"[%s] 未使能,无法设置参数\\n\", dev->name); return; } switch(param) { case RELAY_PARAM_DELAY: printf(\"[%s] 设置延迟: %d毫秒\\n\", dev->name, value); break; default: printf(\"[%s] 未知参数: %d\\n\", dev->name, param); }}// 继电器资源销毁static void relay_destroy(Peripheral* dev) { printf(\"[%s] 销毁资源 (地址: 0x%02X)\\n\", dev->name, dev->address); free(dev);}// 创建继电器设备Peripheral* create_relay(int address) { Peripheral* relay = (Peripheral*)malloc(sizeof(Peripheral)); if (!relay) return NULL; relay->name = \"电磁继电器\"; relay->address = address; relay->status = 0; // 初始禁用状态 relay->enable = relay_enable; relay->disable = relay_disable; relay->set_param = relay_set_param; relay->destroy = relay_destroy; return relay;}// -------------------------- 外设工厂定义 --------------------------// 外设类型枚举typedef enum { PERIPHERAL_MOTOR, // 电机 PERIPHERAL_DISPLAY, // 显示屏 PERIPHERAL_RELAY // 继电器} PeripheralType;// 外设工厂:根据类型和地址创建对应外设Peripheral* peripheral_factory_create(PeripheralType type, int address) { switch(type) { case PERIPHERAL_MOTOR: return create_motor(address); case PERIPHERAL_DISPLAY: return create_display(address); case PERIPHERAL_RELAY: return create_relay(address); default: printf(\"未知外设类型: %d\\n\", type); return NULL; }}// -------------------------- 客户端示例(工业控制逻辑) --------------------------// 外设控制通用函数(体现多态性)void peripheral_operate(Peripheral* dev) { // 使能设备 dev->enable(dev); // 设置设备特定参数(不同设备参数含义不同,但调用方式统一) if (strcmp(dev->name, \"直流电机\") == 0) { dev->set_param(dev, MOTOR_PARAM_SPEED, 70); dev->set_param(dev, MOTOR_PARAM_DIRECTION, 1); } else if (strcmp(dev->name, \"OLED显示屏\") == 0) { dev->set_param(dev, DISPLAY_PARAM_BRIGHTNESS, 80); dev->set_param(dev, DISPLAY_PARAM_CONTRAST, 50); } else if (strcmp(dev->name, \"电磁继电器\") == 0) { dev->set_param(dev, RELAY_PARAM_DELAY, 100); } // 禁用设备 dev->disable(dev);}int main() { // 通过工厂创建不同外设(地址用于区分硬件接口) Peripheral* motor = peripheral_factory_create(PERIPHERAL_MOTOR, 0x01); Peripheral* display = peripheral_factory_create(PERIPHERAL_DISPLAY, 0x02); Peripheral* relay = peripheral_factory_create(PERIPHERAL_RELAY, 0x03); if (!motor || !display || !relay) { printf(\"设备创建失败\\n\"); return -1; } // 统一操作不同外设 printf(\"=== 电机操作 ===\\n\"); peripheral_operate(motor); printf(\"\\n=== 显示屏操作 ===\\n\"); peripheral_operate(display); printf(\"\\n=== 继电器操作 ===\\n\"); peripheral_operate(relay); // 销毁资源 motor->destroy(motor); display->destroy(display); relay->destroy(relay); return 0;}