一、工厂模式到底在解决什么问题?

说实话,我刚入行那会儿,写代码特别「直白」。

比如要创建一个对象,直接 new 就完事了。但后来项目越来越大,我发现这种写法有个致命问题——一旦需要修改对象的创建逻辑,我得满世界找那些 new 关键字。改一个地方还好,改十几个地方,那简直是噩梦。

工厂模式,说白了就是帮我们把「创建对象」这件事封装起来。你不需要关心对象是怎么 new 出来的,你只需要告诉工厂:「我要一个什么东西」,工厂给你造出来。

我个人习惯把工厂模式分成三种:简单工厂、工厂方法、抽象工厂。它们层层递进,解决不同复杂度的问题。

核心思想:将对象的创建与使用分离,客户端不直接实例化具体类,而是通过工厂来获取实例。

二、简单工厂:最朴素的「代工厂」

2.1 定义

简单工厂,其实不是一个正式的设计模式,更像是一种编程习惯。它通过一个静态方法,根据传入的参数来决定创建哪个具体产品。

2.2 我遇到过的场景

我记得有一次做支付对接,需要支持微信、支付宝、银联三种支付方式。如果每次都在业务代码里写 if (type == "wechat"),那代码会变得又臭又长。

用简单工厂就清爽多了:

public class PaymentFactory {
    public static Payment create(String type) {
        if ("wechat".equals(type)) {
            return new WechatPayment();
        } else if ("alipay".equals(type)) {
            return new AlipayPayment();
        } else if ("unionpay".equals(type)) {
            return new UnionPayment();
        }
        throw new IllegalArgumentException("不支持的支付类型");
    }
}

客户端调用:

Payment payment = PaymentFactory.create("wechat");
payment.pay(100.0);

你看,业务代码里再也不需要出现具体的支付类了。想换支付方式?改工厂里的逻辑就行。

避坑指南:我曾经在一个项目里把简单工厂的 if-else 写了几十个分支,结果每次新增产品都要改工厂类,违反了「开闭原则」。简单工厂适合产品种类少、变化不频繁的场景。

2.3 简单工厂的优缺点

优点 缺点
实现简单,容易理解 工厂类职责过重,新增产品需要修改工厂
客户端与具体产品解耦 不满足开闭原则
适合产品种类少的场景 产品过多时,工厂逻辑会变得臃肿

三、工厂方法:把创建权交给子类

3.1 定义

工厂方法模式,把简单工厂的「大锅饭」拆成了「小灶」。它定义了一个创建对象的接口,但让子类决定实例化哪个类。说白了,就是每个产品对应一个工厂

3.2 为什么需要它?

你想想看,简单工厂里所有产品都在一个工厂里创建。如果产品越来越多,那个工厂类会变得无比庞大。而且每次新增产品,你都得改工厂类,这很不「优雅」。

工厂方法怎么解决?每个产品都有自己的工厂。新增产品时,你只需要新增一个工厂类,不需要修改已有的代码。

// 工厂接口
public interface PaymentFactory {
    Payment create();
}

// 具体工厂
public class WechatPaymentFactory implements PaymentFactory {
    @Override
    public Payment create() {
        return new WechatPayment();
    }
}

public class AlipayPaymentFactory implements PaymentFactory {
    @Override
    public Payment create() {
        return new AlipayPayment();
    }
}

// 客户端
PaymentFactory factory = new WechatPaymentFactory();
Payment payment = factory.create();
payment.pay(100.0);

我的经验:工厂方法模式特别适合那些产品类型稳定,但需要频繁扩展的场景。比如插件系统,每个插件都有自己的工厂,互不干扰。

3.3 工厂方法的优缺点

优点 缺点
符合开闭原则,扩展性好 类的数量增加,系统复杂度上升
每个工厂职责单一 客户端需要知道具体工厂类
适合产品种类多、变化频繁的场景 引入抽象层,增加了理解难度

四、抽象工厂:创建产品族

4.1 定义

抽象工厂模式,是工厂方法的升级版。它用来创建一组相关或相互依赖的对象,也就是「产品族」。

举个例子:一个 UI 组件库,有按钮、输入框、弹窗。如果我要支持「浅色主题」和「深色主题」,每个主题下都有按钮、输入框、弹窗。这时候抽象工厂就派上用场了。

4.2 代码示例

// 抽象产品
public interface Button { void render(); }
public interface Input { void render(); }

// 具体产品 - 浅色主题
public class LightButton implements Button {
    public void render() { System.out.println("渲染浅色按钮"); }
}
public class LightInput implements Input {
    public void render() { System.out.println("渲染浅色输入框"); }
}

// 具体产品 - 深色主题
public class DarkButton implements Button {
    public void render() { System.out.println("渲染深色按钮"); }
}
public class DarkInput implements Input {
    public void render() { System.out.println("渲染深色输入框"); }
}

// 抽象工厂
public interface UIFactory {
    Button createButton();
    Input createInput();
}

// 具体工厂
public class LightUIFactory implements UIFactory {
    public Button createButton() { return new LightButton(); }
    public Input createInput() { return new LightInput(); }
}

public class DarkUIFactory implements UIFactory {
    public Button createButton() { return new DarkButton(); }
    public Input createInput() { return new DarkInput(); }
}

// 客户端
UIFactory factory = new LightUIFactory();
Button btn = factory.createButton();
Input input = factory.createInput();
btn.render();
input.render();

关键点:抽象工厂保证客户端使用的产品都是同一个「族」的。你不会出现浅色按钮配深色输入框这种不协调的情况。

4.3 抽象工厂的优缺点

优点 缺点
保证产品族内产品的一致性 扩展产品族困难(需要修改抽象工厂接口)
客户端与具体产品完全解耦 系统复杂度较高
符合开闭原则(对产品族扩展开放) 不适合产品族变化频繁的场景

五、三种工厂模式对比

嗯,这里我画了一张图,帮你快速理清三者的关系:

三种工厂模式对比 简单工厂 一个工厂类 根据参数创建不同产品 适用:产品少、变化少 缺点:违反开闭原则 工厂方法 每个产品一个工厂 子类决定创建哪个产品 适用:产品多、扩展频繁 缺点:类数量增多 抽象工厂 创建一组相关产品 保证产品族一致性 适用:产品族、主题切换 缺点:扩展产品族困难 复杂度递增,灵活性也递增

六、如何选择?

我个人的经验是:

  • 产品种类少,且不太会变 → 简单工厂就够了,别过度设计
  • 产品种类多,但每个产品独立 → 工厂方法,扩展起来舒服
  • 需要创建一组配套的产品 → 抽象工厂,保证一致性

一个小建议:别一上来就用抽象工厂。我见过太多项目,明明只需要一个简单工厂,硬是搞出了三层抽象,最后维护的人想骂娘。从简单开始,随着需求变化再重构,这才是务实的态度。

好了,三种工厂模式的定义和区别,大概就是这些。说白了,它们都是在帮我们管理对象的创建,只是抽象层次不同。你想想看,你的项目里哪些地方可以用工厂模式优化一下?


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