文章目录
1. 什么是单例模式?
单例模式(Singleton Pattern)是最简单的设计模式之一,它保证一个类仅有一个实例,并提供一个访问它的全局访问点。在C语言中,我们通常通过全局变量和函数来实现这一模式。
2. 为什么需要单例模式?
- 确保某个类只有一个实例
- 提供对该实例的全局访问点
- 控制共享资源的访问
3. 实际应用场景
单例模式在很多场景下都很有用,比如:
- 日志管理器
- 数据库连接池
- 配置管理器
- 缓存系统
4. 代码实现
下面我们以一个日志管理器为例,展示如何在C语言中实现单例模式。
4.1 UML 关系图列
4.2 头文件 (logger.h)
#ifndef LOGGER_H
#define LOGGER_H
#include <stdio.h>
// 日志管理器结构体
typedef struct {
FILE* log_file;
} Logger;
// 获取日志管理器实例
Logger* get_logger_instance(void);
// 写入日志
void log_message(Logger* logger, const char* message);
// 清理日志管理器
void destroy_logger(void);
#endif // LOGGER_H
4.3 实现文件 (logger.c)
#include "logger.h"
#include <stdlib.h>
#include <string.h>
#include <time.h>
// 静态实例指针
static Logger* instance = NULL;
Logger* get_logger_instance(void) {
if (instance == NULL) {
// 延迟初始化
instance = (Logger*)malloc(sizeof(Logger));
if (instance != NULL) {
instance->log_file = fopen("app.log", "a");
if (instance->log_file == NULL) {
free(instance);
instance = NULL;
return NULL;
}
}
}
return instance;
}
void log_message(Logger* logger, const char* message) {
if (logger != NULL && logger->log_file != NULL) {
// 获取当前时间
time_t now;
time(&now);
char* time_str = ctime(&now);
time_str[strlen(time_str) - 1] = '\0'; // 移除换行符
// 写入带时间戳的日志
fprintf(logger->log_file, "[%s] %s\n", time_str, message);
fflush(logger->log_file);
}
}
void destroy_logger(void) {
if (instance != NULL) {
if (instance->log_file != NULL) {
fclose(instance->log_file);
}
free(instance);
instance = NULL;
}
}
4.4 使用示例 (main.c)
#include "logger.h"
#include <stdio.h>
int main() {
// 获取日志实例
Logger* logger = get_logger_instance();
if (logger == NULL) {
printf("Failed to create logger instance\n");
return 1;
}
// 写入一些日志
log_message(logger, "Application started");
log_message(logger, "Processing data...");
log_message(logger, "Data processing completed");
// 验证单例特性
Logger* another_logger = get_logger_instance();
log_message(another_logger, "This is the same logger instance");
// 程序结束前清理
destroy_logger();
return 0;
}
5. 代码分析
5.1 关键设计点
-
单一实例保证
- 使用静态指针 static Logger* instance 确保全局唯一性
- 通过判空实现延迟初始化
-
资源管理
- 提供 destroy_logger() 函数进行资源清理
- 合理处理内存分配和文件操作
-
线程安全考虑
- 当前实现是非线程安全的
- 在多线程环境下需要添加互斥锁
5.2 实现特点
- 延迟初始化(懒汉式)
- 全局访问点
- 自动资源管理
- 简单易用的API
6. 编译和运行
gcc -c logger.c -o logger.o
gcc -c main.c -o main.o
gcc logger.o main.o -o program
7. 注意事项
- 在多线程环境下需要添加线程安全机制
- 注意资源的正确释放
- 错误处理要完善
- 日志文件路径最好可配置
8. 改进建议
- 添加日志级别(INFO、WARNING、ERROR等)
- 实现日志轮转功能
- 添加格式化输出支持
- 增加配置选项(如日志文件路径、缓冲区大小等)
9. 总结
单例模式虽然简单,但在实际应用中非常有用。通过本文的实例,我们不仅学习了单例模式的实现,还了解了在C语言中进行面向对象设计的一些技巧。这个日志管理器的实现虽然基础,但包含了完整的单例模式实现思路,可以作为其他单例应用的参考。
参考资料
- 《设计模式:可复用面向对象软件的基础》
- C语言编程规范
- 现代C语言编程实践