设计模式(二):工厂模式

一、工厂模式介绍

工厂模式本质是将对象创建与使用 解耦,避免业务代码直接依赖具体实现。 根据系统复杂度和变化维度不同,常见有简单工厂、工厂方法和抽象工厂三种形式。

第一,简单工厂。 简单工厂通过一个工厂类,根据参数决定创建哪一种具体对象。 它的优点是实现简单、集中管理对象创建 ,但缺点是新增类型需要修改工厂代码,不符合 开闭原则,更适合类型稳定、变化不频繁的场景。

第二, 工厂方法 工厂方法将"创建哪个对象"延迟到子类中完成,每一种产品对应一个具体工厂,通过多态替代条件分支。 它解决了简单工厂扩展性差的问题,符合 开闭原则,适用于"创建流程一致,但具体类型会不断扩展"的场景。

第三,抽象工厂。 抽象工厂用于创建一整套相互关联的对象 ,强调产品族的概念,比如同一套环境下的多个组件必须保持一致。 它的优势是保证产品族一致性,但代价是结构复杂,新增产品类型需要修改所有具体工厂,适合系统初始化阶段做整体选型的场景。

总结来说: 简单工厂关注"创建哪一个对象", 工厂方法关注"如何扩展对象创建", 抽象工厂关注"如何创建一整套相关对象"。 三者没有优劣之分,只有是否匹配当前系统复杂度和变化维度

二、示例:网络服务器中的「连接对象创建」(muduo / reactor 场景)

背景

在一个基于 Reactor 的网络服务器中(比如 muduo):

  • 新连接到来时

  • 都需要创建一个 Connection 对象

  • 创建流程是固定的

比如:

  1. 分配 fd

  2. 设置 socket 选项

  3. 注册到 EventLoop

  4. 绑定回调

  5. 放入连接管理器

但是:

不同业务的连接行为不同:

  • 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 对扩展开放、对修改关闭。


本篇文章讨论了工厂模式,欢迎评论!

相关推荐
杨充15 小时前
10.可测试性实战设计
设计模式·开源·代码规范
杨充15 小时前
9.重构十二式的实战
设计模式·开源·代码规范
杨充15 小时前
6.设计原则的全景图
设计模式·开源·全栈
杨充15 小时前
2.面向对象的特性
设计模式
杨充15 小时前
7.SOLID原则案例汇
设计模式·开源·全栈
杨充15 小时前
8.反模式与坏味道
设计模式·开源·代码规范
杨充15 小时前
3.接口vs抽象类比较
设计模式
咖啡八杯18 小时前
文法、BNF与AST
java·设计模式·解释器模式·ast·文法
咖啡八杯1 天前
GoF设计模式——解释器模式
java·后端·spring·设计模式