c++注意点(11)----设计模式(工厂方法)

发布于:2025-07-30 ⋅ 阅读:(18) ⋅ 点赞:(0)

创建型模式

工厂方法模式是一种创建型设计模式, 其在父类中提供一个创建对象的方法, 允许子类决定实例化对象的类型。

为什么需要工厂方法模式?

看一个 “没有工厂模式” 的痛点场景:

假设你在开发一个游戏,最初只有 “战士” 一种角色,代码可能这样写:

// 早期代码:直接在客户端创建对象
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 <iostream>
#include <string>
#include <memory>

// 产品接口:游戏角色
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<Character> createCharacter() = 0;  // 工厂方法:创建角色
};

// 具体工厂1:战士工厂
class WarriorFactory : public CharacterFactory {
public:
    std::unique_ptr<Character> createCharacter() override {
        std::cout << "=== 战士工厂创建角色 ===" << std::endl;
        return std::make_unique<Warrior>();  // 创建战士
    }
};

// 具体工厂2:法师工厂
class MageFactory : public CharacterFactory {
public:
    std::unique_ptr<Character> createCharacter() override {
        std::cout << "=== 法师工厂创建角色 ===" << std::endl;
        return std::make_unique<Mage>();  // 创建法师
    }
};

// 具体工厂3:弓箭手工厂
class ArcherFactory : public CharacterFactory {
public:
    std::unique_ptr<Character> createCharacter() override {
        std::cout << "=== 弓箭手工厂创建角色 ===" << std::endl;
        return std::make_unique<Archer>();  // 创建弓箭手
    }
};

// 客户端:游戏角色选择系统
class GameSystem {
public:
    // 根据选择的工厂创建角色并执行操作
    static void playWithCharacter(CharacterFactory& factory) {
        auto character = factory.createCharacter();  // 通过工厂获取角色
        std::cout << "创建了角色:" << character->getName() << std::endl;
        
        // 角色执行战斗操作
        character->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 <stdio.h>
#include <stdlib.h>
#include <string.h>

// -------------------------- 外设抽象产品 --------------------------
// 外设抽象接口(相当于抽象类)
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;
}
    


网站公告

今日签到

点亮在社区的每一天
去签到