一、工厂模式介绍
工厂模式本质是将对象创建与使用 解耦,避免业务代码直接依赖具体实现。 根据系统复杂度和变化维度不同,常见有简单工厂、工厂方法和抽象工厂三种形式。
第一,简单工厂。 简单工厂通过一个工厂类,根据参数决定创建哪一种具体对象。 它的优点是实现简单、集中管理对象创建 ,但缺点是新增类型需要修改工厂代码,不符合 开闭原则,更适合类型稳定、变化不频繁的场景。
第二, 工厂方法 。 工厂方法将"创建哪个对象"延迟到子类中完成,每一种产品对应一个具体工厂,通过多态替代条件分支。 它解决了简单工厂扩展性差的问题,符合 开闭原则,适用于"创建流程一致,但具体类型会不断扩展"的场景。
第三,抽象工厂。 抽象工厂用于创建一整套相互关联的对象 ,强调产品族的概念,比如同一套环境下的多个组件必须保持一致。 它的优势是保证产品族一致性,但代价是结构复杂,新增产品类型需要修改所有具体工厂,适合系统初始化阶段做整体选型的场景。
总结来说: 简单工厂关注"创建哪一个对象", 工厂方法关注"如何扩展对象创建", 抽象工厂关注"如何创建一整套相关对象"。 三者没有优劣之分,只有是否匹配当前系统复杂度和变化维度。
二、示例:网络服务器中的「连接对象创建」(muduo / reactor 场景)
背景
在一个基于 Reactor 的网络服务器中(比如 muduo):
-
新连接到来时
-
都需要创建一个
Connection对象 -
创建流程是固定的
比如:
-
分配 fd
-
设置 socket 选项
-
注册到 EventLoop
-
绑定回调
-
放入连接管理器
但是:
不同业务的连接行为不同:
-
HTTP 连接
-
WebSocket 连接
-
RPC 连接
-
内部控制连接
如果不用工厂方法,会发生什么?
❌ 典型写法
cpp
void Server::onNewConnection(int fd) {
if (type == HTTP) {
conn = new HttpConnection(fd);
}
else if (type == WS) {
conn = new WebSocketConnection(fd);
}
else if (type == RPC) { conn = new RpcConnection(fd);
}
}
工程问题(你可以直接说):
-
Server强依赖所有具体连接类型 -
每加一种连接,必须修改核心 IO 代码
-
违反开闭原则
-
测试和扩展都困难
工厂方法怎么解这个问题?
抽象一个"连接工厂"
cpp
class ConnectionFactory {
public:
virtual ~ConnectionFactory() = default;
virtual std::unique_ptr<Connection> create(int fd) = 0;
};
每种协议一个工厂(重点)
cpp
class HttpConnectionFactory : public ConnectionFactory {
public:std::unique_ptr<Connection> create(int fd) override {auto conn = std::make_unique<HttpConnection>(fd);
conn->initHttpContext();return conn;
}
};
class RpcConnectionFactory : public ConnectionFactory {
public:std::unique_ptr<Connection> create(int fd) override {auto conn = std::make_unique<RpcConnection>(fd);
conn->initCodec();return conn;
}
};
Server 层发生了什么变化?
cpp
void Server::onNewConnection(int fd) {
auto conn = factory_->create(fd);
connectionManager_.add(std::move(conn));
}
🔥 关键点:
Server 不再关心"创建哪种连接", 只负责统一的创建流程和生命周期管理。
这为什么是「必须用工厂方法」?
这里必须用工厂方法,而不是简单工厂,是因为连接类型会持续扩展,而 Server 是稳定核心模块,不能频繁修改。
Q:为什么不用简单工厂?
答:
因为连接类型是开放变化的,如果用简单工厂,每加一种协议都要改工厂逻辑,本质还是 if-else 膨胀。
Q:那抽象工厂呢?
答:
抽象工厂更适合一次性创建一整套组件,比如 Connection + Codec + Dispatcher。 这里只是单一对象创建,工厂方法更合适。
总结
在网络服务器中,新连接的创建流程是固定的,但具体连接类型会不断扩展,比如 HTTP、RPC、WebSocket。 如果在 Server 中直接 if-else 创建,会导致核心 IO 代码频繁修改。 我通过工厂方法,把连接创建延迟到具体工厂中,用多态替代条件分支,保证 Server 对扩展开放、对修改关闭。
本篇文章讨论了工厂模式,欢迎评论!