扫码加入

  • 正文
  • 相关推荐
申请入驻 产业图谱

嵌入式编程模型 | 抽象工厂模式

2025/06/20
702
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

一、抽象工厂模式

抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供一个接口用于创建相关或依赖对象的家族,而无需指定它们的具体类。

在需要高兼容性的嵌入式系统中,抽象工厂模式能显著降低多平台适配成本,确保硬件组件间的兼容性,是构建可移植嵌入式框架的核心模式

上一篇我们分享了:嵌入式编程模型 | 简单工厂模式

抽象工厂模式(Abstract Factory Pattern)与简单工厂模式有很多相似之处。我们先做个对比:

特性 简单工厂模式 抽象工厂模式
嵌入式应用 单一设备驱动管理 整套硬件平台适配
适用场景 产品类型少且变化不频繁 需要创建多个相关产品的系统
抽象级别 产品级别抽象 工厂级别抽象
创建对象 单个产品 产品家族(多个相关产品)
工厂类型 单一工厂类 抽象工厂+多个具体工厂实现类
扩展性 添加新产品需修改工厂类 添加新产品族只需新增工厂类

简单工厂模式适用于产品类型少且变化不频繁的场景。如嵌入式中对单一设备驱动管理,比如管理LCD驱动:

抽象工厂模式适用于需要创建多个相关产品的系统。如嵌入式中对整个硬件平台的管理。

抽象工厂模式的核心包含四个关键部分:

    抽象工厂(Abstract Factory):声明创建一系列产品的方法。具体工厂(Concrete Factory):实现抽象工厂的方法,创建具体产品。抽象产品(Abstract Product):声明产品接口。具体产品(Concrete Product):实现抽象产品接口,定义具体产品。

其中,第2~4点就是简单工厂模式的要点。即简单工厂模式加上第1点的抽象工厂这个要点就构成了抽象工厂模式。

二、嵌入式:多平台硬件抽象层

设备需要支持不同平台(STM32/ESP32等),每个平台有兼容的输入、输出驱动。

1、代码

C语言版本:

#include <stdio.h>
#include <stdbool.h>

// 抽象产品(Abstract Product)
typedefstruct {
    void (*Init)(void);
    void (*Draw)(int x, int y);
} DisplayDriver;

typedefstruct {
    void (*Init)(void);
    bool (*ReadButton)(void);
} InputDriver;

// 具体产品实现 - STM32平台
void stm32_disp_init(void) {
    printf("STM32 Display Initializedn");
}

void stm32_draw(int x, int y) {
    printf("STM32 Drawing at (%d, %d)n", x, y);
}

void stm32_button_init(void) {
    printf("STM32 Button Initializedn");
}

bool stm32_read_button(void) {
    printf("STM32 Button Readn");
    returntrue; // 模拟按下状态
}

// 具体产品实现 - ESP32平台
void esp32_disp_init(void) {
    printf("ESP32 Display Initializedn");
}

void esp32_draw(int x, int y) {
    printf("ESP32 Drawing at (%d, %d)n", x, y);
}

void esp32_button_init(void) {
    printf("ESP32 Button Initializedn");
}

bool esp32_read_button(void) {
    printf("ESP32 Button Readn");
    returnfalse; // 模拟未按下状态
}

// 抽象工厂(Abstract Factory)
typedefstruct {
    DisplayDriver display;
    InputDriver input;
} HWPlatform;

// 具体工厂(Concrete Factory) - STM32平台
const HWPlatform stm32_platform = {
    {stm32_disp_init, stm32_draw},
    {stm32_button_init, stm32_read_button}
};

// 具体工厂(Concrete Factory) - ESP32平台
const HWPlatform esp32_platform = {
    {esp32_disp_init, esp32_draw},
    {esp32_button_init, esp32_read_button}
};

int main() {
    // 选择平台 - 通过定义USE_STM32宏来选择
    #if defined(USE_STM32)
        constchar* platform_name = "STM32";
        const HWPlatform* platform = &stm32_platform;
    #else
        constchar* platform_name = "ESP32";
        const HWPlatform* platform = &esp32_platform;
    #endif
    
    printf("Running on %s platformn", platform_name);
    
    // 初始化显示
    platform->display.Init();
    
    // 初始化输入
    platform->input.Init();
    
    // 绘制图形
    platform->display.Draw(10, 20);
    platform->display.Draw(30, 40);
    
    // 读取按钮状态
    bool buttonState = platform->input.ReadButton();
    printf("Button state: %sn", buttonState ? "PRESSED" : "RELEASED");
    
    return0;
}

C ++版本:

#include <iostream>
#include <cstdint>

// 抽象产品接口
struct DisplayDriver {
    void (*Init)(void);
    void (*Draw)(int x, int y);
};

struct InputDriver {
    void (*Init)(void);
    bool (*ReadButton)(void);
};

// 具体产品实现 - STM32平台
namespace STM32 {
    void DisplayInit() {
        std::cout << "[STM32] Display initializedn";
    }
    
    void DisplayDraw(int x, int y) {
        std::cout << "[STM32] Drawing at (" << x << ", " << y << ")n";
    }
    
    void InputInit() {
        std::cout << "[STM32] Input initializedn";
    }
    
    bool InputReadButton() {
        std::cout << "[STM32] Reading buttonn";
        returntrue; // 模拟按钮被按下
    }
}

// 具体产品实现 - ESP32平台
namespace ESP32 {
    void DisplayInit() {
        std::cout << "[ESP32] Display initializedn";
    }
    
    void DisplayDraw(int x, int y) {
        std::cout << "[ESP32] Drawing at (" << x << ", " << y << ")n";
    }
    
    void InputInit() {
        std::cout << "[ESP32] Input initializedn";
    }
    
    bool InputReadButton() {
        std::cout << "[ESP32] Reading buttonn";
        returnfalse; // 模拟按钮未被按下
    }
}

// 抽象工厂
class HWPlatform {
public:
    const DisplayDriver& GetDisplayDriver() const { return display; }
    const InputDriver& GetInputDriver() const { return input; }
    
    virtual void PrintPlatformInfo() const {
        std::cout << "Generic Hardware Platformn";
    }
    
protected:
    DisplayDriver display;
    InputDriver input;
};

// 具体工厂 - STM32平台
class STM32Platform :public HWPlatform {
public:
    STM32Platform() {
        display.Init = STM32::DisplayInit;
        display.Draw = STM32::DisplayDraw;
        input.Init = STM32::InputInit;
        input.ReadButton = STM32::InputReadButton;
    }
    
    void PrintPlatformInfo() const override {
        std::cout << "n=== STM32 Hardware Platform ===n";
    }
};

// 具体工厂 - ESP32平台
class ESP32Platform :public HWPlatform {
public:
    ESP32Platform() {
        display.Init = ESP32::DisplayInit;
        display.Draw = ESP32::DisplayDraw;
        input.Init = ESP32::InputInit;
        input.ReadButton = ESP32::InputReadButton;
    }
    
    void PrintPlatformInfo() const override {
        std::cout << "n=== ESP32 Hardware Platform ===n";
    }
};

// 使用示例
int main() {
    std::cout << "=== Embedded Hardware Platform Demo ===n";
    
    // 平台选择
    #if defined(USE_STM32)
        STM32Platform platform;
        std::cout << "Selected platform: STM32n";
    #else
        ESP32Platform platform;
        std::cout << "Selected platform: ESP32n";
    #endif

    // 打印平台信息
    platform.PrintPlatformInfo();
    
    // 初始化硬件
    std::cout << "nInitializing hardware...n";
    platform.GetDisplayDriver().Init();
    platform.GetInputDriver().Init();
    
    // 使用显示驱动
    std::cout << "nDrawing on display...n";
    platform.GetDisplayDriver().Draw(5, 10);
    platform.GetDisplayDriver().Draw(15, 25);
    platform.GetDisplayDriver().Draw(30, 40);
    
    // 读取输入状态
    std::cout << "nReading input...n";
    bool buttonState = platform.GetInputDriver().ReadButton();
    std::cout << "Button state: " << (buttonState ? "PRESSED" : "RELEASED") << "n";
    
    return0;
}

2、优缺点分析

(1)优点

① 符合开闭原则

开闭原则 (The Open/Closed Principle, OCP) :软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的。

    • 初始支持:STM32和ESP32新增平台:添加Nordic nRF52支持

      • 新增

NRF52Platform

      • 工厂类新增nRF52显示/输入驱动

无需修改

    • 现有STM32/ESP32代码

② 接口统一化

// 统一的硬件操作接口
platform->display.Init();
platform->input.Init();
platform->display.Draw(10, 20);
platform->display.Draw(30, 40);
bool buttonState = platform->input.ReadButton();

③ 平台无关性设计

    业务逻辑与硬件解耦代码复用率高,减少平台移植工作量(新平台只需实现具体工厂和产品)
(2)缺点

① 扩展新产品困难

例如:

    初始设计:显示+输入新增需求:摄像头模块修改成本:

    • 修改所有3个平台工厂类添加3个摄像头驱动实现更新所有测试用例

三、总结:何时选择抽象工厂

相关推荐

登录即可解锁
  • 海量技术文章
  • 设计资源下载
  • 产业链客户资源
  • 写文章/发需求
立即登录

本公众号专注于嵌入式技术,包括但不限于C/C++、嵌入式、物联网、Linux等编程学习笔记,同时,公众号内包含大量的学习资源。欢迎关注,一同交流学习,共同进步!