简单工厂模式:工厂模式的“学前班”

说实话,每次带新人看设计模式,我都不建议直接从GoF 23种模式开干。为什么?因为太抽象了。你想想看,一个刚入行的程序员,连对象怎么创建都还没玩明白,你跟他讲抽象工厂、建造者模式,那不是找虐吗?

我个人习惯,先讲简单工厂模式。虽然它不属于GoF的23种模式,但它是理解工厂模式的绝佳起点。说白了,它就是工厂模式的“学前班”——让你先感受一下“把创建对象的逻辑抽出来”这件事到底有多爽。

什么是简单工厂?

简单工厂,顾名思义,就是一个“专门负责创建对象”的类。你给它一个参数,它给你返回一个对应的对象实例。调用者不需要关心这个对象是怎么new出来的,也不需要关心它属于哪个具体类。

我在项目中遇到过这样一个场景:早期我们做支付系统,对接了微信、支付宝、银联三种渠道。一开始代码写得很随意,到处是if (type == "wechat") { return new WechatPay(); }这样的判断。后来需求一变,要加个云闪付,好家伙,满世界找if语句,改得我头皮发麻。

嗯,这时候简单工厂就派上用场了。

核心结构

简单工厂模式由三部分组成:

  • 工厂类:负责创建产品对象,通常包含一个静态方法
  • 产品接口/抽象类:定义产品的公共行为
  • 具体产品类:实现产品接口的具体类

你看,就这么简单。没有复杂的继承链,没有抽象工厂的多层嵌套。就是一个工厂,一个接口,一堆实现类。

核心思想:将对象的创建和使用分离。调用方只依赖产品接口,不依赖具体实现类。

代码示例:支付渠道工厂

先定义一个支付接口:

// 支付接口
public interface IPayment {
    void pay(double amount);
}

然后实现几个具体支付类:

// 微信支付
public class WechatPay implements IPayment {
    @Override
    public void pay(double amount) {
        System.out.println("微信支付:" + amount + "元");
    }
}

// 支付宝支付
public class AlipayPay implements IPayment {
    @Override
    public void pay(double amount) {
        System.out.println("支付宝支付:" + amount + "元");
    }
}

// 银联支付
public class UnionPay implements IPayment {
    @Override
    public void pay(double amount) {
        System.out.println("银联支付:" + amount + "元");
    }
}

重点来了,工厂类长这样:

// 简单工厂
public class PaymentFactory {
    public static IPayment createPayment(String type) {
        if ("wechat".equalsIgnoreCase(type)) {
            return new WechatPay();
        } else if ("alipay".equalsIgnoreCase(type)) {
            return new AlipayPay();
        } else if ("union".equalsIgnoreCase(type)) {
            return new UnionPay();
        } else {
            throw new IllegalArgumentException("不支持的支付类型:" + type);
        }
    }
}

调用方就清爽多了:

// 客户端代码
IPayment payment = PaymentFactory.createPayment("wechat");
payment.pay(100.0);

你看,调用方根本不知道WechatPay这个类存在。它只认IPayment接口。哪天我们要把微信支付换成新的实现,只要改工厂内部,调用方一行代码都不用动。

简单工厂的优缺点

优点 缺点
将对象的创建和使用解耦 工厂类职责过重,新增产品需要修改工厂类
客户端只需知道产品接口,降低依赖 违反了开闭原则(对扩展开放,对修改关闭)
代码集中管理,便于统一维护 产品类型较多时,工厂内部if-else会变得臃肿

避坑指南:我曾经在一个项目中,把简单工厂用到了极致——一个工厂里塞了30多种产品的创建逻辑。结果每次加新产品都要改工厂类,改一次测试一次,烦不胜烦。后来我重构成了工厂方法模式,才算是解脱了。

所以我的建议是:如果产品类型不超过5种,且变化不频繁,简单工厂完全够用。否则,趁早考虑更灵活的模式。

什么时候用简单工厂?

说白了,简单工厂适合以下场景:

  • 产品类型不多,且相对稳定
  • 调用方不想直接依赖具体产品类
  • 创建逻辑比较简单,不需要复杂的初始化过程

举个例子,你做一个日志系统,有文件日志、控制台日志、数据库日志三种。这三种短期内不会增加,用简单工厂就挺合适。

知识体系图

下面这张图,我画出了简单工厂模式的核心逻辑。你看一眼就能明白:工厂类就是那个“中间人”,把客户端和具体产品隔离开。

客户端 PaymentFactory createPayment(type) <<接口>> IPayment WechatPay AlipayPay UnionPay 调用 依赖 创建 图例: 调用/创建 依赖 实现

小技巧:在实际项目中,我习惯把工厂类的创建方法定义为静态的。这样调用方连工厂对象都不用new,直接PaymentFactory.createPayment("wechat")就完事了。省事,也符合直觉。

简单工厂 vs 直接new

你可能会问:我直接new WechatPay()不就行了?干嘛要多一层工厂?

问得好。直接new的问题在于:

  • 如果WechatPay的构造函数改了,所有new它的地方都得改
  • 如果以后要替换成NewWechatPay,你得满世界找new语句
  • 如果创建逻辑复杂了(比如需要读取配置、校验参数),每个调用方都得重复写一遍

简单工厂把这些都收拢到一个地方。改一处,全局生效。这就是“封装变化”的思想——把容易变化的部分隔离出来。

嗯,说白了,简单工厂就是让你少写重复代码,少踩坑。


好了,简单工厂就讲到这里。它虽然简单,但“将对象的创建和使用分离”这个思想,是所有工厂模式的根基。你把这个搞明白了,后面学工厂方法、抽象工厂,就会觉得顺理成章。

公众号:蓝海资料掘金营,微信deep3321