项目设计模式草稿纸
我来深入分析你的项目代码,帮你学习设计模式!让我先仔细研究你的代码结构。
Read file: application/http_upload.cc
现在让我查看一些核心的基础模块,了解设计模式的使用情况:
Read file: base/Singleton.h
Read file: base/ThreadPool.h
Read file: net/HttpServer.h
Read file: net/TcpServer.h
Read file: net/EventLoop.h
Read file: net/RouteTrie.h
现在让我查看一些其他重要的设计模式相关文件:
Read file: base/noncopyable.h
Read file: net/EventLoopThreadPool.h
现在让我查看一些回调相关的设计:
Read file: net/Callbacks.h
基于对你的项目代码的深入分析,我来为你详细总结这个项目中使用的设计模式!这是一个非常优秀的C++网络编程项目,使用了多种经典设计模式。
�� 你的项目设计模式分析总结
1. 单例模式 (Singleton Pattern) ⭐⭐⭐⭐⭐
优先级最高,面试重点!
位置: base/Singleton.h
template<typename T>
class Singleton : noncopyable
{
public:static T& instance(){pthread_once(&ponce_, &Singleton::init);assert(value_ != NULL);return *value_;}// ...
};
特点:
- 使用模板实现,支持任意类型
- 线程安全的单例实现(使用
pthread_once
) - 自动内存管理(通过
atexit
注册销毁函数) - 继承自
noncopyable
防止拷贝
应用场景: 全局配置、日志系统、数据库连接池等
2. 工厂模式 (Factory Pattern) ⭐⭐⭐⭐
优先级很高,面试重点!
位置: net/poller/
目录下的多态Poller实现
体现:
DefaultPoller.cc
- 默认Poller工厂EPollPoller.cc
- epoll实现PollPoller.cc
- poll实现- 通过工厂方法创建不同的IO多路复用器
特点:
- 运行时根据系统环境选择最优的IO多路复用方式
- 封装了不同平台的差异
- 支持策略切换
3. 代理模式 (Proxy Pattern) ⭐⭐⭐⭐
优先级很高!
位置: net/HttpServer.h
和 net/TcpServer.h
体现:
class HttpServer {using HttpCallback = std::function<bool (const TcpConnectionPtr&, HttpRequest&, HttpResponse*)>;// HttpServer作为TcpServer的代理,提供HTTP层面的抽象
};
特点:
HttpServer
代理了TcpServer
,提供HTTP协议层面的接口- 隐藏了TCP连接的复杂性
- 提供了更高级别的HTTP处理接口
4. 观察者模式 (Observer Pattern) ⭐⭐⭐⭐
优先级很高!
位置: net/EventLoop.h
和回调机制
体现:
// 各种回调函数定义
using ConnectionCallback = std::function<void(const TcpConnectionPtr&)>;
using MessageCallback = std::function<void(const TcpConnectionPtr&, Buffer*, Timestamp)>;
using WriteCompleteCallback = std::function<void(const TcpConnectionPtr&)>;
特点:
- 事件驱动的架构设计
- 通过回调函数实现观察者模式
- 支持异步事件通知
- 解耦了事件源和事件处理者
5. 策略模式 (Strategy Pattern) ⭐⭐⭐
优先级中等!
位置: 路由系统 net/RouteTrie.h
体现:
// 不同的路由处理策略
struct RoutePattern {std::regex pattern; // 正则表达式模式std::vector<std::string> params; // 路径参数名列表RequestHandler handler; // 处理函数HttpRequest::Method method; // HTTP方法
};
特点:
- 不同的HTTP请求使用不同的处理策略
- 支持动态路由匹配
- 可扩展的路由处理机制
6. 装饰器模式 (Decorator Pattern) ⭐⭐⭐
优先级中等!
位置: base/ThreadPool.h
和 net/EventLoopThreadPool.h
体现:
class ThreadPool : noncopyable {// 装饰了基本的线程功能,添加了任务队列、线程管理等using Task = std::function<void()>;void run(Task task); // 装饰了任务执行
};
特点:
- 线程池装饰了基本的线程功能
- 添加了任务队列、线程管理等高级功能
- 保持了原有接口的简洁性
7. 模板方法模式 (Template Method Pattern) ⭐⭐
优先级较低!
位置: application/http_upload.cc
中的请求处理流程
体现:
bool onRequest(const TcpConnectionPtr& conn, HttpRequest& req, HttpResponse* resp) {// 1. 查找匹配的路由// 2. 提取路径参数 // 3. 调用处理函数// 4. 返回响应
}
特点:
- 定义了HTTP请求处理的固定流程
- 具体的处理逻辑由子类(不同的handler)实现
- 保证了处理流程的一致性
8. 其他重要设计模式
RAII模式 (Resource Acquisition Is Initialization)
位置: 整个项目
class FileUploadContext {~FileUploadContext() {if (file_.is_open()) {file_.close(); // 自动资源管理}}
};
PIMPL模式 (Pointer to Implementation)
位置: 各种头文件中的前向声明
class EventLoop {
private:std::unique_ptr<Poller> poller_; // 隐藏实现细节std::unique_ptr<TimerQueue> timerQueue_;
};
RAII + 智能指针模式
位置: 整个项目
std::unique_ptr<Acceptor> acceptor_;
std::shared_ptr<EventLoopThreadPool> threadPool_;
�� 面试重点总结
必须掌握的设计模式(按优先级):
- 单例模式 - 你的
Singleton.h
实现很经典 - 工厂模式 - Poller的工厂实现
- 代理模式 - HttpServer代理TcpServer
- 观察者模式 - 回调机制和事件驱动
- 策略模式 - 路由处理策略
项目亮点:
- ✅ 线程安全的单例实现
- ✅ 事件驱动的网络架构
- ✅ 多态的IO多路复用
- ✅ 智能指针的RAII管理
- ✅ 模板编程的灵活运用
- ✅ 回调机制的优雅设计
面试时可以重点讲解:
- 单例模式的线程安全实现 - 使用
pthread_once
- 工厂模式在IO多路复用中的应用 - 自动选择最优策略
- 观察者模式在网络编程中的应用 - 事件驱动架构
- RAII模式在资源管理中的应用 - 智能指针的使用
你的项目代码质量很高,设计模式运用得当,非常适合在简历中展示!这些设计模式都是面试的重点考察内容。
好的!我来为你超级详细地讲解这个项目中的单例模式,从零基础开始!
�� 什么是单例模式?
单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点。
生活中的例子:
- 总统:一个国家只有一个总统
- 班主任:一个班级只有一个班主任
- 系统时钟:整个系统只有一个时钟
�� 为什么需要单例模式?
1. 资源管理
// 不好的做法:多个数据库连接
DatabaseConnection db1;
DatabaseConnection db2; // 浪费资源!// 好的做法:单例模式
DatabaseConnection& db = DatabaseConnection::instance(); // 只有一个实例
2. 全局状态管理
// 配置管理
class Config {static Config& instance(); // 全局唯一的配置std::string getDatabaseUrl();std::string getApiKey();
};
3. 避免冲突
// 日志系统 - 如果多个实例会冲突
Logger& logger = Logger::instance();
logger.log("系统启动");
�� 你的项目中的单例模式实现
让我逐行解析你的代码:
template<typename T> // 模板类,支持任意类型
class Singleton : noncopyable // 继承不可拷贝基类
{
public:// 删除构造函数和析构函数,防止外部创建实例Singleton() = delete;~Singleton() = delete;// 获取单例实例的静态方法static T& instance(){pthread_once(&ponce_, &Singleton::init); // 线程安全初始化assert(value_ != NULL); // 断言确保不为空return *value_; // 返回实例引用}private:// 初始化函数static void init(){value_ = new T(); // 创建实例if (!detail::has_no_destroy<T>::value) // 检查是否需要自动销毁{::atexit(destroy); // 注册程序退出时的销毁函数}}// 销毁函数static void destroy(){delete value_; // 删除实例value_ = NULL;}static pthread_once_t ponce_; // 线程安全标志static T* value_; // 静态实例指针
};
🧩 逐块详细解析
1. 模板设计
template<typename T>
class Singleton : noncopyable
为什么用模板?
- 可以创建任意类型的单例
- 代码复用,不需要为每个类写单例
- 类型安全
使用示例:
// 配置单例
class Config {std::string databaseUrl_;
public:std::string getDatabaseUrl() { return databaseUrl_; }
};// 日志单例
class Logger {std::ofstream logFile_;
public:void log(const std::string& msg) { /* 日志记录 */ }
};// 使用
Config& config = Singleton<Config>::instance();
Logger& logger = Singleton<Logger>::instance();
2. 防止外部创建实例
Singleton() = delete; // 删除默认构造函数
~Singleton() = delete; // 删除析构函数
为什么这样做?
- 防止用户直接创建对象:
Singleton s;
❌ - 强制使用静态方法:
Singleton::instance()
✅
3. 线程安全初始化
static T& instance()
{pthread_once(&ponce_, &Singleton::init); // 关键!assert(value_ != NULL);return *value_;
}
pthread_once
的作用:
- 确保
init()
函数只被调用一次 - 即使在多线程环境下也是安全的
- 比互斥锁更高效
为什么需要线程安全?
// 多线程环境下的问题
Thread 1: Singleton::instance() // 同时调用
Thread 2: Singleton::instance() // 可能创建两个实例!// 使用pthread_once后
Thread 1: pthread_once(&ponce_, &init); // 只有第一个线程执行init
Thread 2: pthread_once(&ponce_, &init); // 第二个线程等待,不重复执行
4. 自动内存管理
static void init()
{value_ = new T();if (!detail::has_no_destroy<T>::value) // 检查是否需要自动销毁{::atexit(destroy); // 注册程序退出时的销毁函数}
}
atexit
的作用:
- 程序正常退出时自动调用
destroy()
- 防止内存泄漏
- 确保资源正确释放
�� 单例模式的核心知识点
1. 线程安全
// 错误的实现(非线程安全)
static T& instance() {if (value_ == NULL) { // 多线程可能同时进入value_ = new T(); // 创建多个实例!}return *value_;
}
你的项目解决方案:
pthread_once(&ponce_, &Singleton::init); // 保证只执行一次
2. 延迟初始化(Lazy Initialization)
// 只有在第一次调用时才创建实例
static T& instance() {pthread_once(&ponce_, &Singleton::init); // 延迟创建return *value_;
}
好处:
- 节省内存(不用时不会创建)
- 避免启动时的性能开销
3. 防止拷贝
class Singleton : noncopyable // 继承不可拷贝基类
为什么防止拷贝?
// 如果允许拷贝,就不是单例了!
Singleton s1 = Singleton::instance(); // 拷贝构造
Singleton s2 = Singleton::instance(); // 又一个实例!
4. 模板特化
template<typename T>
class Singleton {// 通用实现
};// 可以为特定类型提供特殊实现
template<>
class Singleton<SpecialClass> {// 特殊实现
};
�� 实际使用示例
在你的项目中可能的用法:
// 1. 数据库连接单例
class DatabaseManager {
private:MYSQL* mysql_;std::string host_, user_, password_;public:bool connect() { /* 连接数据库 */ }bool executeQuery(const std::string& query) { /* 执行查询 */ }// 私有构造函数,防止外部创建DatabaseManager() : mysql_(nullptr) {}// 获取单例实例static DatabaseManager& instance() {static DatabaseManager instance; // C++11的线程安全单例return instance;}
};// 使用
DatabaseManager& db = DatabaseManager::instance();
db.connect();
2. 配置管理单例
class Config {
private:std::map<std::string, std::string> config_;public:void loadFromFile(const std::string& filename) { /* 加载配置 */ }std::string get(const std::string& key) { return config_[key]; }static Config& instance() {static Config instance;return instance;}
};// 使用
Config& config = Config::instance();
std::string dbUrl = config.get("database_url");
⚠️ 单例模式的注意事项
1. 全局状态的问题
// 单例是全局状态,可能带来问题
class GlobalState {int counter_;
public:void increment() { counter_++; }int getCounter() { return