工厂模式与单例模式在嵌入式系统中的应用¶
概述¶
在嵌入式系统开发中,对象的创建和管理是一个重要的设计问题。工厂模式和单例模式是两种最常用的创建型设计模式,它们帮助我们更好地控制对象的创建过程,提高代码的可维护性和可扩展性。
工厂模式提供了一种创建对象的接口,让子类决定实例化哪个类。单例模式确保一个类只有一个实例,并提供全局访问点。这两种模式在嵌入式系统中有着广泛的应用,特别是在硬件驱动、资源管理和系统配置等场景中。
学习目标¶
完成本文学习后,你将能够:
- 理解工厂模式和单例模式的基本概念和设计原理
- 掌握在C语言中实现这两种模式的方法
- 了解这两种模式在嵌入式系统中的典型应用场景
- 能够根据实际需求选择合适的创建型模式
- 理解这两种模式的优缺点和使用注意事项
工厂模式详解¶
什么是工厂模式¶
工厂模式(Factory Pattern)是一种创建型设计模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,而是通过使用一个共同的接口来指向新创建的对象。
核心思想: - 将对象的创建与使用分离 - 客户端不需要知道具体类的名称 - 通过工厂方法创建对象 - 易于扩展新的产品类型
工厂模式的类型¶
工厂模式主要有三种形式:
- 简单工厂模式(Simple Factory)
- 一个工厂类根据参数创建不同类型的对象
-
最简单但扩展性较差
-
工厂方法模式(Factory Method)
- 定义创建对象的接口,由子类决定实例化哪个类
-
符合开闭原则,易于扩展
-
抽象工厂模式(Abstract Factory)
- 提供创建一系列相关或相互依赖对象的接口
- 适用于产品族的创建
在嵌入式系统中,简单工厂模式和工厂方法模式最为常用。
简单工厂模式实现¶
让我们通过一个串口驱动的例子来理解简单工厂模式:
// uart_driver.h
#ifndef UART_DRIVER_H
#define UART_DRIVER_H
#include <stdint.h>
// 串口类型枚举
typedef enum {
UART_TYPE_USART1,
UART_TYPE_USART2,
UART_TYPE_USART3,
UART_TYPE_MAX
} UartType_t;
// 串口驱动接口
typedef struct {
void (*init)(void); // 初始化
void (*send)(uint8_t *data, uint16_t len); // 发送数据
uint16_t (*receive)(uint8_t *buf, uint16_t len); // 接收数据
void (*deinit)(void); // 反初始化
} UartDriver_t;
// 工厂函数:根据类型创建串口驱动
UartDriver_t* UartFactory_Create(UartType_t type);
#endif
// uart_driver.c
#include "uart_driver.h"
#include <stdlib.h>
// USART1驱动实现
static void usart1_init(void) {
// USART1初始化代码
// 配置GPIO、时钟、波特率等
}
static void usart1_send(uint8_t *data, uint16_t len) {
// USART1发送实现
for (uint16_t i = 0; i < len; i++) {
// 等待发送缓冲区空
while (!(USART1->SR & USART_SR_TXE));
USART1->DR = data[i];
}
}
static uint16_t usart1_receive(uint8_t *buf, uint16_t len) {
// USART1接收实现
uint16_t count = 0;
while (count < len && (USART1->SR & USART_SR_RXNE)) {
buf[count++] = USART1->DR;
}
return count;
}
static void usart1_deinit(void) {
// USART1反初始化
}
// USART1驱动实例
static UartDriver_t usart1_driver = {
.init = usart1_init,
.send = usart1_send,
.receive = usart1_receive,
.deinit = usart1_deinit
};
// USART2驱动实现(类似USART1)
static void usart2_init(void) { /* ... */ }
static void usart2_send(uint8_t *data, uint16_t len) { /* ... */ }
static uint16_t usart2_receive(uint8_t *buf, uint16_t len) { /* ... */ }
static void usart2_deinit(void) { /* ... */ }
static UartDriver_t usart2_driver = {
.init = usart2_init,
.send = usart2_send,
.receive = usart2_receive,
.deinit = usart2_deinit
};
// USART3驱动实现(类似USART1)
static void usart3_init(void) { /* ... */ }
static void usart3_send(uint8_t *data, uint16_t len) { /* ... */ }
static uint16_t usart3_receive(uint8_t *buf, uint16_t len) { /* ... */ }
static void usart3_deinit(void) { /* ... */ }
static UartDriver_t usart3_driver = {
.init = usart3_init,
.send = usart3_send,
.receive = usart3_receive,
.deinit = usart3_deinit
};
/**
* @brief 工厂函数:创建串口驱动实例
* @param type: 串口类型
* @retval 串口驱动指针,失败返回NULL
*/
UartDriver_t* UartFactory_Create(UartType_t type) {
UartDriver_t *driver = NULL;
// 根据类型返回对应的驱动实例
switch (type) {
case UART_TYPE_USART1:
driver = &usart1_driver;
break;
case UART_TYPE_USART2:
driver = &usart2_driver;
break;
case UART_TYPE_USART3:
driver = &usart3_driver;
break;
default:
driver = NULL;
break;
}
// 初始化驱动
if (driver != NULL && driver->init != NULL) {
driver->init();
}
return driver;
}
使用示例:
// main.c
#include "uart_driver.h"
int main(void) {
// 通过工厂创建USART1驱动
UartDriver_t *uart1 = UartFactory_Create(UART_TYPE_USART1);
if (uart1 != NULL) {
// 使用驱动发送数据
uint8_t data[] = "Hello World!";
uart1->send(data, sizeof(data) - 1);
// 接收数据
uint8_t rx_buf[128];
uint16_t len = uart1->receive(rx_buf, sizeof(rx_buf));
}
// 创建USART2驱动
UartDriver_t *uart2 = UartFactory_Create(UART_TYPE_USART2);
while (1) {
// 主循环
}
}
设计优点: - 客户端不需要知道具体的驱动实现细节 - 统一的接口,易于使用 - 添加新的串口类型只需扩展工厂函数 - 驱动实现与使用解耦
工厂模式的应用场景¶
在嵌入式系统中,工厂模式常用于以下场景:
- 硬件驱动管理
- 不同型号的传感器驱动
- 多种通信接口(UART、SPI、I2C)
-
不同的显示屏驱动
-
协议栈实现
- 不同的网络协议(TCP、UDP、MQTT)
-
多种数据格式解析器(JSON、XML、Protobuf)
-
设备抽象层
- 跨平台的HAL层实现
-
不同芯片的外设驱动
-
插件系统
- 可动态加载的功能模块
- 可配置的算法实现
选择工厂模式的时机: - 需要创建的对象类型在编译时无法确定 - 对象创建逻辑复杂,需要封装 - 需要统一管理对象的创建过程 - 希望降低客户端与具体类的耦合
单例模式详解¶
什么是单例模式¶
单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问这个实例。
核心思想: - 控制实例数量,确保只有一个 - 提供全局访问点 - 延迟初始化(可选) - 线程安全(多线程环境)
单例模式的实现方式¶
在C语言中,单例模式有多种实现方式:
- 饿汉式(Eager Initialization)
- 程序启动时就创建实例
-
线程安全,但可能浪费资源
-
懒汉式(Lazy Initialization)
- 第一次使用时才创建实例
-
节省资源,但需要考虑线程安全
-
静态变量方式
- 利用C语言的静态变量特性
- 最简单,最常用
饿汉式单例实现¶
// system_config.h
#ifndef SYSTEM_CONFIG_H
#define SYSTEM_CONFIG_H
#include <stdint.h>
#include <stdbool.h>
// 系统配置结构体
typedef struct {
uint32_t system_clock; // 系统时钟频率
uint32_t uart_baudrate; // 串口波特率
uint8_t log_level; // 日志级别
bool watchdog_enabled; // 看门狗使能
uint16_t adc_sample_rate; // ADC采样率
} SystemConfig_t;
// 获取系统配置单例
SystemConfig_t* SystemConfig_GetInstance(void);
// 配置接口
void SystemConfig_SetClock(uint32_t clock);
uint32_t SystemConfig_GetClock(void);
void SystemConfig_SetBaudrate(uint32_t baudrate);
uint32_t SystemConfig_GetBaudrate(void);
#endif
// system_config.c
#include "system_config.h"
// 静态单例实例(饿汉式)
static SystemConfig_t g_system_config = {
.system_clock = 72000000, // 默认72MHz
.uart_baudrate = 115200, // 默认115200
.log_level = 2, // 默认INFO级别
.watchdog_enabled = true, // 默认使能看门狗
.adc_sample_rate = 1000 // 默认1kHz采样率
};
/**
* @brief 获取系统配置单例实例
* @retval 系统配置指针
*
* @note 饿汉式实现,程序启动时就已创建实例
* 线程安全,无需额外同步机制
*/
SystemConfig_t* SystemConfig_GetInstance(void) {
return &g_system_config;
}
/**
* @brief 设置系统时钟频率
* @param clock: 时钟频率(Hz)
*/
void SystemConfig_SetClock(uint32_t clock) {
SystemConfig_t *config = SystemConfig_GetInstance();
config->system_clock = clock;
}
/**
* @brief 获取系统时钟频率
* @retval 时钟频率(Hz)
*/
uint32_t SystemConfig_GetClock(void) {
SystemConfig_t *config = SystemConfig_GetInstance();
return config->system_clock;
}
/**
* @brief 设置串口波特率
* @param baudrate: 波特率
*/
void SystemConfig_SetBaudrate(uint32_t baudrate) {
SystemConfig_t *config = SystemConfig_GetInstance();
config->uart_baudrate = baudrate;
}
/**
* @brief 获取串口波特率
* @retval 波特率
*/
uint32_t SystemConfig_GetBaudrate(void) {
SystemConfig_t *config = SystemConfig_GetInstance();
return config->uart_baudrate;
}
使用示例:
// main.c
#include "system_config.h"
int main(void) {
// 获取系统配置单例
SystemConfig_t *config = SystemConfig_GetInstance();
// 修改配置
SystemConfig_SetClock(84000000); // 设置为84MHz
SystemConfig_SetBaudrate(921600); // 设置高速波特率
// 在其他模块中也可以获取同一个实例
uint32_t clock = SystemConfig_GetClock();
// 配置会在整个程序中保持一致
while (1) {
// 主循环
}
}
懒汉式单例实现¶
懒汉式单例在第一次使用时才创建实例,适合资源占用较大的对象:
// logger.h
#ifndef LOGGER_H
#define LOGGER_H
#include <stdint.h>
// 日志级别
typedef enum {
LOG_LEVEL_DEBUG = 0,
LOG_LEVEL_INFO,
LOG_LEVEL_WARN,
LOG_LEVEL_ERROR
} LogLevel_t;
// 日志器结构体
typedef struct {
LogLevel_t level; // 当前日志级别
uint32_t log_count; // 日志计数
bool initialized; // 初始化标志
} Logger_t;
// 获取日志器单例
Logger_t* Logger_GetInstance(void);
// 日志接口
void Logger_Log(LogLevel_t level, const char *format, ...);
void Logger_Debug(const char *format, ...);
void Logger_Info(const char *format, ...);
void Logger_Warn(const char *format, ...);
void Logger_Error(const char *format, ...);
#endif
// logger.c
#include "logger.h"
#include <stdio.h>
#include <stdarg.h>
// 静态单例实例指针(懒汉式)
static Logger_t *g_logger_instance = NULL;
// 静态实例存储
static Logger_t g_logger_storage;
/**
* @brief 初始化日志器
* @param logger: 日志器指针
*/
static void Logger_Init(Logger_t *logger) {
if (logger != NULL && !logger->initialized) {
logger->level = LOG_LEVEL_INFO; // 默认INFO级别
logger->log_count = 0;
logger->initialized = true;
// 初始化串口等资源
// UART_Init();
}
}
/**
* @brief 获取日志器单例实例
* @retval 日志器指针
*
* @note 懒汉式实现,第一次调用时才初始化
* 在单线程环境下安全
* 多线程环境需要添加互斥锁保护
*/
Logger_t* Logger_GetInstance(void) {
// 第一次调用时初始化
if (g_logger_instance == NULL) {
g_logger_instance = &g_logger_storage;
Logger_Init(g_logger_instance);
}
return g_logger_instance;
}
/**
* @brief 输出日志
* @param level: 日志级别
* @param format: 格式化字符串
*/
void Logger_Log(LogLevel_t level, const char *format, ...) {
Logger_t *logger = Logger_GetInstance();
// 检查日志级别
if (level < logger->level) {
return;
}
// 格式化输出
va_list args;
va_start(args, format);
// 输出日志级别标识
const char *level_str[] = {"[DEBUG]", "[INFO]", "[WARN]", "[ERROR]"};
printf("%s ", level_str[level]);
// 输出日志内容
vprintf(format, args);
printf("\n");
va_end(args);
// 更新计数
logger->log_count++;
}
/**
* @brief 输出DEBUG级别日志
*/
void Logger_Debug(const char *format, ...) {
Logger_t *logger = Logger_GetInstance();
if (LOG_LEVEL_DEBUG < logger->level) return;
va_list args;
va_start(args, format);
printf("[DEBUG] ");
vprintf(format, args);
printf("\n");
va_end(args);
}
/**
* @brief 输出INFO级别日志
*/
void Logger_Info(const char *format, ...) {
Logger_t *logger = Logger_GetInstance();
if (LOG_LEVEL_INFO < logger->level) return;
va_list args;
va_start(args, format);
printf("[INFO] ");
vprintf(format, args);
printf("\n");
va_end(args);
}
/**
* @brief 输出WARN级别日志
*/
void Logger_Warn(const char *format, ...) {
Logger_t *logger = Logger_GetInstance();
if (LOG_LEVEL_WARN < logger->level) return;
va_list args;
va_start(args, format);
printf("[WARN] ");
vprintf(format, args);
printf("\n");
va_end(args);
}
/**
* @brief 输出ERROR级别日志
*/
void Logger_Error(const char *format, ...) {
Logger_t *logger = Logger_GetInstance();
if (LOG_LEVEL_ERROR < logger->level) return;
va_list args;
va_start(args, format);
printf("[ERROR] ");
vprintf(format, args);
printf("\n");
va_end(args);
}
使用示例:
// main.c
#include "logger.h"
int main(void) {
// 第一次调用时会自动初始化
Logger_Info("System starting...");
// 后续调用使用同一个实例
Logger_Debug("Debug information");
Logger_Warn("Warning message");
Logger_Error("Error occurred!");
// 在任何地方都可以使用日志器
// 无需传递指针,全局可访问
while (1) {
// 主循环
}
}
线程安全的单例实现¶
在RTOS环境下,需要考虑线程安全问题:
// thread_safe_singleton.c
#include "FreeRTOS.h"
#include "semphr.h"
// 单例实例
static ResourceManager_t *g_resource_manager = NULL;
static ResourceManager_t g_resource_storage;
// 互斥锁
static SemaphoreHandle_t g_singleton_mutex = NULL;
/**
* @brief 获取资源管理器单例(线程安全版本)
* @retval 资源管理器指针
*
* @note 使用双重检查锁定(Double-Checked Locking)
* 确保多线程环境下的安全性
*/
ResourceManager_t* ResourceManager_GetInstance(void) {
// 第一次检查(无锁,快速路径)
if (g_resource_manager == NULL) {
// 创建互斥锁(只创建一次)
if (g_singleton_mutex == NULL) {
g_singleton_mutex = xSemaphoreCreateMutex();
}
// 获取互斥锁
xSemaphoreTake(g_singleton_mutex, portMAX_DELAY);
// 第二次检查(有锁,确保只初始化一次)
if (g_resource_manager == NULL) {
g_resource_manager = &g_resource_storage;
ResourceManager_Init(g_resource_manager);
}
// 释放互斥锁
xSemaphoreGive(g_singleton_mutex);
}
return g_resource_manager;
}
线程安全要点: - 使用互斥锁保护初始化过程 - 双重检查锁定减少锁竞争 - 确保只初始化一次 - 避免死锁和竞态条件
单例模式的应用场景¶
在嵌入式系统中,单例模式常用于以下场景:
- 系统配置管理
- 全局配置参数
- 系统状态信息
-
运行时参数
-
硬件资源管理
- 唯一的硬件资源(看门狗、RTC)
- 共享的外设(Flash、EEPROM)
-
系统总线管理
-
日志系统
- 统一的日志输出
- 日志级别控制
-
日志缓冲管理
-
任务调度器
- RTOS任务管理器
- 事件管理器
-
定时器管理器
-
驱动管理器
- 设备驱动注册表
- 中断管理器
- DMA控制器
选择单例模式的时机: - 系统中只需要一个实例 - 需要全局访问点 - 实例创建开销大,需要延迟初始化 - 需要严格控制实例数量
综合实例:传感器管理系统¶
让我们通过一个完整的传感器管理系统来综合应用工厂模式和单例模式:
// sensor_manager.h
#ifndef SENSOR_MANAGER_H
#define SENSOR_MANAGER_H
#include <stdint.h>
#include <stdbool.h>
// 传感器类型
typedef enum {
SENSOR_TYPE_TEMPERATURE,
SENSOR_TYPE_HUMIDITY,
SENSOR_TYPE_PRESSURE,
SENSOR_TYPE_MAX
} SensorType_t;
// 传感器接口
typedef struct {
bool (*init)(void);
float (*read)(void);
void (*deinit)(void);
const char *name;
} Sensor_t;
// 传感器管理器(单例)
typedef struct {
Sensor_t *sensors[SENSOR_TYPE_MAX]; // 传感器数组
uint8_t sensor_count; // 传感器数量
bool initialized; // 初始化标志
} SensorManager_t;
// 单例接口
SensorManager_t* SensorManager_GetInstance(void);
// 工厂接口
Sensor_t* SensorFactory_Create(SensorType_t type);
// 管理接口
bool SensorManager_RegisterSensor(SensorType_t type);
float SensorManager_ReadSensor(SensorType_t type);
void SensorManager_PrintAllSensors(void);
#endif
// sensor_manager.c
#include "sensor_manager.h"
#include <stdio.h>
#include <string.h>
// ========== 温度传感器实现 ==========
static bool temp_sensor_init(void) {
printf("Temperature sensor initialized\n");
return true;
}
static float temp_sensor_read(void) {
// 模拟读取温度
return 25.5f;
}
static void temp_sensor_deinit(void) {
printf("Temperature sensor deinitialized\n");
}
static Sensor_t temp_sensor = {
.init = temp_sensor_init,
.read = temp_sensor_read,
.deinit = temp_sensor_deinit,
.name = "Temperature Sensor"
};
// ========== 湿度传感器实现 ==========
static bool humidity_sensor_init(void) {
printf("Humidity sensor initialized\n");
return true;
}
static float humidity_sensor_read(void) {
// 模拟读取湿度
return 60.0f;
}
static void humidity_sensor_deinit(void) {
printf("Humidity sensor deinitialized\n");
}
static Sensor_t humidity_sensor = {
.init = humidity_sensor_init,
.read = humidity_sensor_read,
.deinit = humidity_sensor_deinit,
.name = "Humidity Sensor"
};
// ========== 气压传感器实现 ==========
static bool pressure_sensor_init(void) {
printf("Pressure sensor initialized\n");
return true;
}
static float pressure_sensor_read(void) {
// 模拟读取气压
return 1013.25f;
}
static void pressure_sensor_deinit(void) {
printf("Pressure sensor deinitialized\n");
}
static Sensor_t pressure_sensor = {
.init = pressure_sensor_init,
.read = pressure_sensor_read,
.deinit = pressure_sensor_deinit,
.name = "Pressure Sensor"
};
// ========== 传感器工厂实现 ==========
/**
* @brief 传感器工厂:根据类型创建传感器
* @param type: 传感器类型
* @retval 传感器指针,失败返回NULL
*/
Sensor_t* SensorFactory_Create(SensorType_t type) {
Sensor_t *sensor = NULL;
switch (type) {
case SENSOR_TYPE_TEMPERATURE:
sensor = &temp_sensor;
break;
case SENSOR_TYPE_HUMIDITY:
sensor = &humidity_sensor;
break;
case SENSOR_TYPE_PRESSURE:
sensor = &pressure_sensor;
break;
default:
sensor = NULL;
break;
}
// 初始化传感器
if (sensor != NULL && sensor->init != NULL) {
if (!sensor->init()) {
sensor = NULL;
}
}
return sensor;
}
// ========== 传感器管理器单例实现 ==========
static SensorManager_t g_sensor_manager = {
.sensor_count = 0,
.initialized = false
};
/**
* @brief 获取传感器管理器单例
* @retval 传感器管理器指针
*/
SensorManager_t* SensorManager_GetInstance(void) {
if (!g_sensor_manager.initialized) {
// 初始化管理器
memset(g_sensor_manager.sensors, 0, sizeof(g_sensor_manager.sensors));
g_sensor_manager.sensor_count = 0;
g_sensor_manager.initialized = true;
printf("Sensor Manager initialized\n");
}
return &g_sensor_manager;
}
/**
* @brief 注册传感器到管理器
* @param type: 传感器类型
* @retval 成功返回true,失败返回false
*/
bool SensorManager_RegisterSensor(SensorType_t type) {
SensorManager_t *manager = SensorManager_GetInstance();
// 检查是否已注册
if (manager->sensors[type] != NULL) {
printf("Sensor type %d already registered\n", type);
return false;
}
// 使用工厂创建传感器
Sensor_t *sensor = SensorFactory_Create(type);
if (sensor == NULL) {
printf("Failed to create sensor type %d\n", type);
return false;
}
// 注册传感器
manager->sensors[type] = sensor;
manager->sensor_count++;
printf("Sensor '%s' registered successfully\n", sensor->name);
return true;
}
/**
* @brief 读取传感器数据
* @param type: 传感器类型
* @retval 传感器读数,失败返回0.0f
*/
float SensorManager_ReadSensor(SensorType_t type) {
SensorManager_t *manager = SensorManager_GetInstance();
// 检查传感器是否已注册
if (type >= SENSOR_TYPE_MAX || manager->sensors[type] == NULL) {
printf("Sensor type %d not registered\n", type);
return 0.0f;
}
// 读取传感器数据
Sensor_t *sensor = manager->sensors[type];
if (sensor->read != NULL) {
return sensor->read();
}
return 0.0f;
}
/**
* @brief 打印所有已注册的传感器信息
*/
void SensorManager_PrintAllSensors(void) {
SensorManager_t *manager = SensorManager_GetInstance();
printf("\n=== Registered Sensors ===\n");
printf("Total count: %d\n", manager->sensor_count);
for (int i = 0; i < SENSOR_TYPE_MAX; i++) {
if (manager->sensors[i] != NULL) {
Sensor_t *sensor = manager->sensors[i];
float value = sensor->read();
printf("- %s: %.2f\n", sensor->name, value);
}
}
printf("========================\n\n");
}
使用示例:
// main.c
#include "sensor_manager.h"
int main(void) {
// 获取传感器管理器单例
SensorManager_t *manager = SensorManager_GetInstance();
// 注册传感器(使用工厂模式创建)
SensorManager_RegisterSensor(SENSOR_TYPE_TEMPERATURE);
SensorManager_RegisterSensor(SENSOR_TYPE_HUMIDITY);
SensorManager_RegisterSensor(SENSOR_TYPE_PRESSURE);
// 打印所有传感器
SensorManager_PrintAllSensors();
// 读取特定传感器
float temp = SensorManager_ReadSensor(SENSOR_TYPE_TEMPERATURE);
printf("Current temperature: %.2f°C\n", temp);
float humidity = SensorManager_ReadSensor(SENSOR_TYPE_HUMIDITY);
printf("Current humidity: %.2f%%\n", humidity);
while (1) {
// 主循环
}
}
运行输出:
Sensor Manager initialized
Temperature sensor initialized
Sensor 'Temperature Sensor' registered successfully
Humidity sensor initialized
Sensor 'Humidity Sensor' registered successfully
Pressure sensor initialized
Sensor 'Pressure Sensor' registered successfully
=== Registered Sensors ===
Total count: 3
- Temperature Sensor: 25.50
- Humidity Sensor: 60.00
- Pressure Sensor: 1013.25
========================
Current temperature: 25.50°C
Current humidity: 60.00%
设计亮点: - 工厂模式负责创建不同类型的传感器 - 单例模式确保只有一个传感器管理器 - 统一的传感器接口,易于扩展 - 管理器集中管理所有传感器 - 客户端代码简洁,易于使用
模式对比与选择¶
工厂模式 vs 单例模式¶
| 对比维度 | 工厂模式 | 单例模式 |
|---|---|---|
| 目的 | 创建对象的接口 | 控制实例数量 |
| 实例数量 | 可以创建多个实例 | 只有一个实例 |
| 访问方式 | 通过工厂方法 | 通过全局访问点 |
| 耦合度 | 降低客户端与具体类的耦合 | 全局访问,耦合度较高 |
| 扩展性 | 易于添加新的产品类型 | 不易扩展 |
| 线程安全 | 通常不需要考虑 | 多线程环境需要考虑 |
| 适用场景 | 需要创建多种类型的对象 | 需要全局唯一的实例 |
组合使用¶
工厂模式和单例模式可以组合使用:
// 单例工厂
typedef struct {
bool initialized;
} DriverFactory_t;
static DriverFactory_t g_driver_factory = {
.initialized = false
};
// 获取工厂单例
DriverFactory_t* DriverFactory_GetInstance(void) {
if (!g_driver_factory.initialized) {
// 初始化工厂
g_driver_factory.initialized = true;
}
return &g_driver_factory;
}
// 工厂方法
Driver_t* DriverFactory_CreateDriver(DriverType_t type) {
DriverFactory_t *factory = DriverFactory_GetInstance();
// 创建驱动...
}
组合优势: - 工厂本身是单例,节省资源 - 统一的创建入口 - 便于管理和监控对象创建
常见问题与解决方案¶
工厂模式常见问题¶
问题1:工厂类过于庞大
当产品类型很多时,工厂类会变得臃肿:
// 不好的做法:所有类型都在一个工厂中
Driver_t* DriverFactory_Create(DriverType_t type) {
switch (type) {
case UART1: return &uart1_driver;
case UART2: return &uart2_driver;
case SPI1: return &spi1_driver;
case SPI2: return &spi2_driver;
case I2C1: return &i2c1_driver;
// ... 几十种类型
}
}
// 好的做法:按类别分离工厂
Driver_t* UartFactory_Create(UartType_t type);
Driver_t* SpiFactory_Create(SpiType_t type);
Driver_t* I2cFactory_Create(I2cType_t type);
问题2:如何添加新产品类型
使用函数指针表实现可扩展的工厂:
typedef Driver_t* (*DriverCreator_t)(void);
typedef struct {
DriverType_t type;
DriverCreator_t creator;
} DriverFactoryEntry_t;
static DriverFactoryEntry_t g_factory_table[] = {
{DRIVER_TYPE_UART1, create_uart1_driver},
{DRIVER_TYPE_UART2, create_uart2_driver},
{DRIVER_TYPE_SPI1, create_spi1_driver},
// 添加新类型只需在这里添加一行
};
Driver_t* DriverFactory_Create(DriverType_t type) {
for (int i = 0; i < sizeof(g_factory_table)/sizeof(g_factory_table[0]); i++) {
if (g_factory_table[i].type == type) {
return g_factory_table[i].creator();
}
}
return NULL;
}
单例模式常见问题¶
问题1:单例的销毁
在嵌入式系统中,通常不需要销毁单例,但如果需要:
void SystemConfig_Destroy(void) {
SystemConfig_t *config = SystemConfig_GetInstance();
// 清理资源
// ...
// 重置单例指针(如果使用懒汉式)
g_system_config = NULL;
}
问题2:单例的测试
单例模式会增加测试难度,可以提供测试接口:
#ifdef UNIT_TEST
// 测试时允许重置单例
void SystemConfig_Reset(void) {
g_system_config.initialized = false;
// 重置其他状态
}
#endif
问题3:单例的依赖注入
为了提高可测试性,可以使用依赖注入:
// 允许注入自定义实例(用于测试)
void SystemConfig_SetInstance(SystemConfig_t *instance) {
g_system_config = instance;
}
最佳实践¶
工厂模式最佳实践¶
- 保持工厂简单
- 工厂只负责创建对象
- 不要在工厂中加入业务逻辑
-
复杂的初始化逻辑应该在对象内部
-
使用配置驱动
-
提供默认实现
-
错误处理
Driver_t* DriverFactory_Create(DriverType_t type) { Driver_t *driver = create_driver(type); if (driver == NULL) { // 记录错误日志 Logger_Error("Failed to create driver type %d", type); return NULL; } // 验证驱动 if (!driver_validate(driver)) { Logger_Error("Driver validation failed"); return NULL; } return driver; }
单例模式最佳实践¶
-
明确初始化时机
-
提供状态查询
-
避免循环依赖
-
考虑资源限制
-
文档化单例
性能考虑¶
工厂模式性能¶
创建开销: - 工厂方法调用开销很小 - 主要开销在对象初始化 - 可以使用对象池优化
// 对象池优化
#define DRIVER_POOL_SIZE 10
static Driver_t g_driver_pool[DRIVER_POOL_SIZE];
static bool g_driver_used[DRIVER_POOL_SIZE];
Driver_t* DriverFactory_CreateFromPool(DriverType_t type) {
// 从池中查找空闲对象
for (int i = 0; i < DRIVER_POOL_SIZE; i++) {
if (!g_driver_used[i]) {
g_driver_used[i] = true;
init_driver(&g_driver_pool[i], type);
return &g_driver_pool[i];
}
}
return NULL; // 池已满
}
void DriverFactory_ReleaseToPool(Driver_t *driver) {
// 归还到池中
for (int i = 0; i < DRIVER_POOL_SIZE; i++) {
if (&g_driver_pool[i] == driver) {
g_driver_used[i] = false;
break;
}
}
}
单例模式性能¶
访问开销: - 饿汉式:无额外开销,直接返回指针 - 懒汉式:第一次调用有初始化开销 - 线程安全版本:有锁竞争开销
优化建议:
// 使用内联函数减少函数调用开销
static inline SystemConfig_t* SystemConfig_GetInstance(void) {
return &g_system_config;
}
// 缓存单例指针
static SystemConfig_t *cached_config = NULL;
void some_function(void) {
// 避免重复调用GetInstance
if (cached_config == NULL) {
cached_config = SystemConfig_GetInstance();
}
// 使用缓存的指针
uint32_t clock = cached_config->system_clock;
}
总结¶
核心要点¶
工厂模式: - 提供创建对象的统一接口 - 将对象创建与使用分离 - 易于扩展新的产品类型 - 适用于需要创建多种类型对象的场景
单例模式: - 确保类只有一个实例 - 提供全局访问点 - 节省系统资源 - 适用于需要全局唯一实例的场景
使用建议¶
何时使用工厂模式: - 对象创建逻辑复杂 - 需要根据条件创建不同类型的对象 - 希望降低客户端与具体类的耦合 - 需要集中管理对象创建
何时使用单例模式: - 系统中只需要一个实例 - 需要全局访问该实例 - 实例创建开销大,需要延迟初始化 - 需要严格控制实例数量
何时避免使用: - 工厂模式:对象类型固定且简单时 - 单例模式:需要多个实例或影响可测试性时
注意事项¶
- 工厂模式注意事项:
- 避免工厂类过于庞大
- 保持工厂方法简单
- 考虑使用配置驱动
-
提供良好的错误处理
-
单例模式注意事项:
- 多线程环境考虑线程安全
- 避免过度使用导致全局状态泛滥
- 注意单例之间的依赖关系
-
考虑可测试性
-
组合使用注意事项:
- 明确各自的职责
- 避免过度设计
- 保持代码简洁
延伸阅读¶
相关设计模式¶
建议继续学习以下相关模式:
- 观察者模式在嵌入式中的应用 - 学习对象间的通知机制
- 策略模式与命令模式 - 学习行为型设计模式
- 抽象工厂模式 - 学习更复杂的工厂模式
推荐资源¶
书籍: - 《设计模式:可复用面向对象软件的基础》(Gang of Four) - 《Head First设计模式》 - 《嵌入式C语言设计模式》
在线资源: - Refactoring Guru - 设计模式 - SourceMaking - 设计模式
实践项目¶
尝试以下项目来巩固所学知识:
- 设备驱动框架
- 使用工厂模式创建不同类型的驱动
- 使用单例模式管理驱动注册表
-
实现统一的驱动接口
-
配置管理系统
- 使用单例模式实现配置管理器
- 支持配置的读取、保存和更新
-
实现配置的持久化存储
-
传感器数据采集系统
- 使用工厂模式创建不同类型的传感器
- 使用单例模式管理传感器列表
- 实现数据采集和处理流程
下一步学习¶
完成本文学习后,建议:
- 实践本文中的代码示例
- 在实际项目中应用这两种模式
- 学习其他创建型设计模式(建造者模式、原型模式)
- 深入学习行为型和结构型设计模式
- 研究设计模式在大型嵌入式项目中的应用
版权声明:本文为嵌入式知识平台原创内容,转载请注明出处。
更新日志: - 2026-03-10:初始版本发布
反馈与建议:如有任何问题或建议,欢迎通过平台反馈功能联系我们。