Java 设计模式精讲:工厂方法模式

Java 设计模式精讲:工厂方法模式

本篇教程将从零开始、由浅入深,用最通俗的语言、最完整的 Java 代码、最贴合实战的场景,结合七大设计原则深度拆解工厂方法模式,帮你彻底吃透这个设计模式,不仅会写,更懂为什么这么写,能在实际项目中灵活落地。


前言:为什么我们需要工厂模式?

在学习工厂方法之前,我们先看一个所有 Java 新手都会写的「坏代码」,这也是工厂模式诞生的核心原因。

假设我们要开发一个「手机销售系统」,需要创建华为、小米两种手机对象,直接调用它们的通话功能:

// 手机接口
public interface Phone {
    void call(); // 通话功能
}

// 华为手机
public class HuaweiPhone implements Phone {
    @Override
    public void call() {
        System.out.println("华为手机通话");
    }
}

// 小米手机
public class XiaomiPhone implements Phone {
    @Override
    public void call() {
        System.out.println("小米手机通话");
    }
}

// 客户端(测试类)
public class Client {
    public static void main(String[] args) {
        // 直接new对象!耦合度极高
        Phone huawei = new HuaweiPhone();
        huawei.call();

        Phone xiaomi = new XiaomiPhone();
        xiaomi.call();
    }
}

这段代码的致命问题(架构视角)

  1. 强耦合:客户端直接依赖具体的实现类(HuaweiPhone/XiaomiPhone),一旦类名修改、构造器变更,客户端代码必须全部修改;
  2. 无法扩展:如果新增苹果手机,客户端必须新增new ApplePhone(),违背「扩展开放、修改关闭」;
  3. 创建逻辑冗余:如果手机创建需要初始化参数、连接数据库、加载配置,所有客户端都要写重复的创建代码;
  4. 违反设计原则:完全依赖具体实现,不依赖抽象,不符合架构设计的核心思想。

工厂模式的核心价值:将「对象的创建」和「对象的使用」分离,客户端只负责使用对象,创建逻辑交给工厂,彻底解耦!

工厂模式分为三类:简单工厂模式(静态工厂)→ 工厂方法模式 → 抽象工厂模式,难度逐级递增。我们遵循「由浅入深」原则,先学基础,再深入核心的工厂方法模式


第一章 设计基石:Java 七大设计原则(通俗精讲)

工厂方法模式是七大设计原则的完美实践,在讲解模式之前,我们必须先吃透这 7 个原则(架构师的核心准则),每个原则用通俗语言 + 极简代码讲解,后面会逐一对应工厂方法的实现。

1.1 单一职责原则(SRP)

核心:一个类 / 接口 / 方法,只负责一件事,职责单一,避免「全能类」。

✅ 好代码:手机类只做手机功能,工厂类只做创建对象。

❌ 坏代码:一个类既创建手机,又实现手机通话,还做销售逻辑。

1.2 开闭原则(OCP)

核心对扩展开放,对修改关闭。新增功能时,不修改原有代码,只新增代码。

这是设计模式的第一原则,也是工厂方法模式的核心目标。

1.3 里氏替换原则(LSP)

核心:子类可以完全替换父类 / 接口,程序功能不受影响。

基于「多态」实现,所有实现类必须遵循父类的契约。

1.4 依赖倒置原则(DIP)

核心依赖抽象,不依赖具体

高层模块(客户端)不依赖低层模块(具体实现),两者都依赖抽象(接口 / 抽象类)。

1.5 接口隔离原则(ISP)

核心:接口要小而专,不要大而全。避免实现类被迫实现不需要的方法。

1.6 迪米特法则(LoD)

核心最少知道原则。一个对象只和「直接朋友」交互,不跟「陌生人」说话,减少类之间的依赖。

1.7 合成复用原则(CRP)

核心:优先使用组合 / 聚合,而不是继承实现复用。

继承会强耦合,组合更灵活,是架构设计的首选复用方式。


第二章 入门铺垫:简单工厂模式(静态工厂)

工厂方法模式是简单工厂的升级优化版,我们先学简单工厂,找到它的缺陷,自然就能理解工厂方法的必要性。

2.1 简单工厂定义

简单工厂(静态工厂):定义一个工厂类,通过静态方法接收参数,创建不同的产品对象

它不属于 GOF23 种设计模式,但它是工厂方法的基础。

2.2 简单工厂代码实现(手机案例)

// 1. 抽象产品:手机接口
public interface Phone {
    void call();
}

// 2. 具体产品:华为手机
public class HuaweiPhone implements Phone {
    @Override
    public void call() {
        System.out.println("华为手机:鸿蒙系统通话");
    }
}

// 3. 具体产品:小米手机
public class XiaomiPhone implements Phone {
    @Override
    public void call() {
        System.out.println("小米手机:MIUI系统通话");
    }
}

// 4. 简单工厂类(核心)
public class SimplePhoneFactory {
    // 静态方法:根据参数创建手机
    public static Phone createPhone(String type) {
        if ("huawei".equals(type)) {
            return new HuaweiPhone();
        } else if ("xiaomi".equals(type)) {
            return new XiaomiPhone();
        } else {
            throw new IllegalArgumentException("不支持的手机类型");
        }
    }
}

// 5. 客户端
public class Client {
    public static void main(String[] args) {
        // 客户端只调用工厂,不直接new对象
        Phone huawei = SimplePhoneFactory.createPhone("huawei");
        huawei.call();

        Phone xiaomi = SimplePhoneFactory.createPhone("xiaomi");
        xiaomi.call();
    }
}

2.3 简单工厂的优点

  1. 客户端不再直接 new 对象,解耦了「创建与使用」;
  2. 统一管理对象创建逻辑,复用性强。

2.4 简单工厂的致命缺陷(违背开闭原则)

如果我们新增苹果手机,必须修改SimplePhoneFactoryif-else代码:

// 新增苹果手机类
public class ApplePhone implements Phone {
    @Override
    public void call() {
        System.out.println("苹果手机:iOS系统通话");
    }
}

// 修改工厂类!违背开闭原则
public class SimplePhoneFactory {
    public static Phone createPhone(String type) {
        if ("huawei".equals(type)) {
            return new HuaweiPhone();
        } else if ("xiaomi".equals(type)) {
            return new XiaomiPhone();
        } else if ("apple".equals(type)) { // 新增代码
            return new ApplePhone();
        } else {
            throw new IllegalArgumentException("不支持的手机类型");
        }
    }
}

核心问题:扩展产品必须修改工厂原有代码,直接违反开闭原则

这就是简单工厂的天花板,想要解决这个问题,就需要工厂方法模式


第三章 核心精讲:工厂方法设计模式

3.1 工厂方法定义(官方 + 通俗)

GOF 官方定义:定义一个创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类

通俗解释

  1. 不再用一个工厂生产所有产品,而是一个产品对应一个专属工厂
  2. 定义抽象工厂接口,具体工厂实现接口,各自生产对应的产品;
  3. 扩展新产品时,只新增产品类 + 工厂类,不修改原有任何代码,完美遵循开闭原则。

3.2 工厂方法的四大核心角色

工厂方法是标准的四层结构,架构清晰,职责明确:

角色 英文 作用 手机案例对应
抽象产品 Product 定义所有产品的公共接口 / 抽象类 Phone接口
具体产品 ConcreteProduct 实现抽象产品,具体的业务对象 HuaweiPhone/XiaomiPhone/ApplePhone
抽象工厂 Factory 定义创建产品的接口,核心工厂方法 PhoneFactory接口
具体工厂 ConcreteFactory 实现抽象工厂,创建对应的具体产品 HuaweiFactory/XiaomiFactory/AppleFactory

3.3 工厂方法完整代码实现(Java 实战)

我们用手机案例重构,严格遵循四大角色,代码可直接复制运行:

第一步:定义抽象产品(Phone 接口)

/**
 * 抽象产品:手机接口
 * 定义所有手机的公共行为
 */
public interface Phone {
    // 通话功能
    void call();
    // 发送短信
    void sendMessage();
}

第二步:定义具体产品(实现 Phone 接口)

/**
 * 具体产品:华为手机
 */
public class HuaweiPhone implements Phone {
    @Override
    public void call() {
        System.out.println("【华为手机】鸿蒙系统 - 高清通话");
    }

    @Override
    public void sendMessage() {
        System.out.println("【华为手机】鸿蒙系统 - 5G短信");
    }
}

/**
 * 具体产品:小米手机
 */
public class XiaomiPhone implements Phone {
    @Override
    public void call() {
        System.out.println("【小米手机】MIUI系统 - 高清通话");
    }

    @Override
    public void sendMessage() {
        System.out.println("【小米手机】MIUI系统 - 5G短信");
    }
}

/**
 * 具体产品:苹果手机(新增产品,无需修改原有代码)
 */
public class ApplePhone implements Phone {
    @Override
    public void call() {
        System.out.println("【苹果手机】iOS系统 - 高清通话");
    }

    @Override
    public void sendMessage() {
        System.out.println("【苹果手机】iOS系统 - iMessage短信");
    }
}

第三步:定义抽象工厂(PhoneFactory 接口)

工厂方法的核心:抽象工厂定义创建产品的方法,不具体实现!

/**
 * 抽象工厂:手机工厂接口
 * 定义工厂方法:创建手机
 */
public interface PhoneFactory {
    // 工厂方法:返回抽象产品,不依赖具体产品
    Phone createPhone();
}

第四步:定义具体工厂(实现 PhoneFactory)

每个产品对应一个专属工厂,只生产自己的产品:

/**
 * 具体工厂:华为工厂 → 只生产华为手机
 */
public class HuaweiFactory implements PhoneFactory {
    @Override
    public Phone createPhone() {
        // 可以添加复杂的创建逻辑:初始化、配置加载、依赖注入
        return new HuaweiPhone();
    }
}

/**
 * 具体工厂:小米工厂 → 只生产小米手机
 */
public class XiaomiFactory implements PhoneFactory {
    @Override
    public Phone createPhone() {
        return new XiaomiPhone();
    }
}

/**
 * 具体工厂:苹果工厂 → 只生产苹果手机(新增工厂,无修改)
 */
public class AppleFactory implements PhoneFactory {
    @Override
    public Phone createPhone() {
        return new ApplePhone();
    }
}

第五步:客户端调用(核心:依赖抽象,不依赖具体)

/**
 * 客户端:使用工厂方法创建对象
 * 只依赖抽象接口,不依赖任何具体实现类!
 */
public class FactoryMethodClient {
    public static void main(String[] args) {
        // 1. 创建华为工厂(抽象工厂引用具体工厂)
        PhoneFactory huaweiFactory = new HuaweiFactory();
        Phone huaweiPhone = huaweiFactory.createPhone();
        huaweiPhone.call();
        huaweiPhone.sendMessage();

        System.out.println("------------------------");

        // 2. 创建小米工厂
        PhoneFactory xiaomiFactory = new XiaomiFactory();
        Phone xiaomiPhone = xiaomiFactory.createPhone();
        xiaomiPhone.call();
        xiaomiPhone.sendMessage();

        System.out.println("------------------------");

        // 3. 新增苹果手机:只新增类,不修改原有代码!
        PhoneFactory appleFactory = new AppleFactory();
        Phone applePhone = appleFactory.createPhone();
        applePhone.call();
        applePhone.sendMessage();
    }
}

运行结果

【华为手机】鸿蒙系统 - 高清通话
【华为手机】鸿蒙系统 - 5G短信
------------------------
【小米手机】MIUI系统 - 高清通话
【小米手机】MIUI系统 - 5G短信
------------------------
【苹果手机】iOS系统 - 高清通话
【苹果手机】iOS系统 - iMessage短信

3.4 工厂方法的核心特性

  1. 延迟实例化:对象的创建由具体工厂决定,客户端不关心创建细节;
  2. 完全解耦:客户端只依赖抽象接口,与具体实现无关;
  3. 完美扩展:新增产品 = 新增产品类 + 新增工厂类,零修改原有代码

第四章 深度契合:工厂方法与七大设计原则(架构师核心分析)

这是本章最核心、最干货的部分!我们逐一对应七大设计原则,结合上面的代码,证明工厂方法是「设计原则的最佳实践」。

4.1 遵循单一职责原则(SRP)

代码佐证

  1. 具体产品(HuaweiPhone):只实现手机的通话、短信功能,职责单一;
  2. 具体工厂(HuaweiFactory):只负责创建华为手机,职责单一;
  3. 客户端:只负责使用对象,不参与创建。

每个类只做一件事,没有「全能类」,完全符合单一职责。

4.2 遵循开闭原则(OCP)

代码佐证

新增苹果手机时,我们没有修改任何原有代码,只新增了ApplePhoneAppleFactory两个类,客户端直接调用即可。

对扩展开放,对修改关闭,这是工厂方法最核心的优势,彻底解决了简单工厂的缺陷。

4.3 遵循里氏替换原则(LSP)

代码佐证

// 抽象工厂引用具体工厂,子类完全替换父类
PhoneFactory factory = new HuaweiFactory();
// 替换为小米工厂,程序功能不受影响
factory = new XiaomiFactory();
Phone phone = factory.createPhone();

所有具体工厂都实现PhoneFactory接口,具体产品都实现Phone接口,子类可以无缝替换父类,程序逻辑不变。

4.4 遵循依赖倒置原则(DIP)

代码佐证

客户端代码只依赖抽象接口

  • 依赖PhoneFactory(抽象工厂),不依赖HuaweiFactory(具体工厂);
  • 依赖Phone(抽象产品),不依赖HuaweiPhone(具体产品)。

高层模块(客户端)和低层模块(具体实现)都依赖抽象,不依赖具体,彻底解耦。

4.5 遵循接口隔离原则(ISP)

代码佐证

  1. Phone接口只定义call()sendMessage()两个核心方法,小而专;
  2. PhoneFactory接口只定义createPhone()一个工厂方法,无冗余方法;
  3. 实现类不需要强制实现任何不需要的方法,接口设计极简。

4.6 遵循迪米特法则(LoD)

代码佐证

客户端的「直接朋友」只有抽象工厂 + 抽象产品,完全不知道具体产品的创建细节、构造器、初始化逻辑。

客户端不与「陌生人」(具体实现类的内部逻辑)交互,最少知道,依赖最少

4.7 遵循合成复用原则(CRP)

代码佐证

客户端通过组合工厂对象(PhoneFactory factory = new HuaweiFactory())实现对象创建,而不是通过继承工厂类来复用创建逻辑。

组合比继承更灵活,无强耦合,符合架构设计的复用准则。


第五章 辩证分析:工厂方法的优点与局限性(架构视角)

作为架构师,我们不能只讲优点,必须客观分析模式的适用边界,避免过度设计。

5.1 工厂方法的核心优点(企业级架构必备)

  1. 彻底解耦:对象创建与使用分离,客户端无需关心创建细节;
  2. 可扩展性拉满:遵循开闭原则,产品扩展零成本;
  3. 代码可读性 / 可维护性极强:四层结构清晰,职责明确,团队协作无压力;
  4. 符合设计原则:完美契合七大原则,是架构级代码的标准;
  5. 多态性:基于接口编程,方便替换产品实现,适配不同业务场景;
  6. 统一创建规范:复杂对象的初始化逻辑(如配置加载、依赖注入)可以封装在工厂中,全局复用。

5.2 工厂方法的局限性(客观存在)

  1. 类数量爆炸:一个产品对应一个工厂,产品越多,类文件越多(比如 10 个产品 = 10 个工厂类);
  2. 系统复杂度提升:增加了抽象层,新手理解成本略高;
  3. 仅支持单一产品结构:工厂方法只能生产一种类型的产品(如只能生产手机,不能同时生产手机 + 耳机),多产品族需要抽象工厂模式;
  4. 不适合简单对象:如果对象创建无逻辑(直接 new),使用工厂方法属于过度设计。

5.3 架构师建议:什么时候用工厂方法?

  • 产品需要频繁扩展,要求严格遵循开闭原则;
  • 对象创建逻辑复杂(需要初始化、加载配置、连接资源);
  • 客户端不关心对象如何创建,只需要使用对象;
  • 框架 / 组件设计,需要定义统一的对象创建规范;
  • 企业级项目,追求代码解耦、可维护、可扩展。

第六章 横向对比:简单工厂 vs 工厂方法 vs 抽象工厂

为了让你彻底区分三种工厂模式,我用架构师视角的表格总结:

对比维度 简单工厂(静态工厂) 工厂方法模式 抽象工厂模式
核心思想 一个工厂生产所有产品 一个工厂生产一种产品 一个工厂生产一族产品
开闭原则 ❌ 违背(修改工厂) ✅ 遵循(新增类) ✅ 遵循
产品结构 单一产品 单一产品等级 多产品族(手机 + 耳机 + 充电器)
代码复杂度
类数量
适用场景 产品少,不常扩展 单一产品,常扩展 多产品族,常扩展
设计原则 部分遵循 完全遵循 完全遵循

一句话总结

  • 小项目、产品固定 → 简单工厂;
  • 单一产品、需要扩展 → 工厂方法(最常用)
  • 多产品族、复杂业务 → 抽象工厂。

第七章 源码洞察:JDK/Spring 中工厂方法的经典应用

学习设计模式的最终目的是看懂源码、落地项目。工厂方法在 Java 生态中无处不在,我带你拆解两个最经典的源码案例:

7.1 JDK 源码:Collection 的 iterator () 方法(最经典)

JDK 集合框架是工厂方法模式的教科书级实现

  1. 抽象产品Iterator<E>(迭代器接口);
  2. 具体产品ArrayList.ItrHashSet.Itr(迭代器实现类);
  3. 抽象工厂Collection<E>(集合接口,定义iterator()工厂方法);
  4. 具体工厂ArrayListHashSet(实现 Collection,创建对应的迭代器)。

源码简化版

// 抽象工厂:Collection
public interface Collection<E> {
    // 工厂方法:创建迭代器(抽象产品)
    Iterator<E> iterator();
}

// 具体工厂:ArrayList
public class ArrayList<E> implements Collection<E> {
    // 实现工厂方法,创建具体产品
    @Override
    public Iterator<E> iterator() {
        return new Itr();
    }
    // 具体产品:迭代器实现类
    private class Itr implements Iterator<E> {
        // 迭代器逻辑
    }
}

// 客户端使用
public class JdkClient {
    public static void main(String[] args) {
        // 抽象工厂引用具体工厂
        Collection<String> list = new ArrayList<>();
        // 调用工厂方法,获取抽象产品
        Iterator<String> iterator = list.iterator();
    }
}

✅ 完全符合工厂方法的四大角色,这就是 JDK 的设计精髓!

7.2 Spring 源码:FactoryBean 接口

Spring 框架是工厂方法的重度使用者FactoryBean是 Spring 自定义 Bean 的核心接口:

  1. 抽象工厂FactoryBean<T>
  2. 具体工厂:自定义UserFactoryBean
  3. 抽象产品Object/ 业务 Bean;
  4. 工厂方法getObject()

Spring 实战代码

// 抽象工厂:Spring的FactoryBean
public interface FactoryBean<T> {
    // 工厂方法:创建Bean对象
    T getObject() throws Exception;
}

// 具体产品:用户对象
public class User {
    private String name;
    // getter/setter
}

// 具体工厂:用户工厂
@Component
public class UserFactoryBean implements FactoryBean<User> {
    @Override
    public User getObject() {
        // 复杂的Bean创建逻辑
        User user = new User();
        user.setName("工厂方法创建的用户");
        return user;
    }
}

// 客户端:Spring容器自动调用工厂方法
@SpringBootApplication
public class SpringClient {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(SpringClient.class);
        // 获取工厂创建的Bean
        User user = context.getBean(User.class);
        System.out.println(user.getName());
    }
}

Spring 用工厂方法实现了Bean 的灵活创建,是框架设计的核心。


第八章 实战优化:解决工厂方法的「类爆炸」问题

工厂方法的唯一缺点是「类太多」,架构师在项目中会用3 种优化方案,既保留开闭原则,又减少类数量:

8.1 方案 1:反射 + 配置文件(无具体工厂)

通过反射动态创建产品,不需要为每个产品写工厂类,彻底解决类爆炸:

// 抽象工厂
public interface PhoneFactory {
    Phone createPhone();
}

// 通用工厂:反射实现
public class ReflectPhoneFactory implements PhoneFactory {
    // 产品全类名(从配置文件读取)
    private Class<? extends Phone> phoneClass;

    public ReflectPhoneFactory(Class<? extends Phone> phoneClass) {
        this.phoneClass = phoneClass;
    }

    @Override
    public Phone createPhone() {
        try {
            // 反射创建对象
            return phoneClass.newInstance();
        } catch (Exception e) {
            throw new RuntimeException("创建失败");
        }
    }
}

// 客户端
public class OptimizeClient {
    public static void main(String[] args) {
        // 一个通用工厂,创建所有产品
        PhoneFactory factory = new ReflectPhoneFactory(HuaweiPhone.class);
        Phone phone = factory.createPhone();
        phone.call();
    }
}

8.2 方案 2:抽象类代替接口(复用公共逻辑)

抽象工厂类代替接口,封装公共创建逻辑,减少重复代码:

// 抽象工厂类(非接口)
public abstract class AbstractPhoneFactory {
    // 公共方法:所有工厂复用
    public void checkQuality() {
        System.out.println("手机质量检测");
    }
    // 抽象工厂方法
    public abstract Phone createPhone();
}

8.3 方案 3:Spring 注解(零工厂类)

直接用 Spring 的@Bean注解,让 Spring 容器作为工厂,完全消除手动工厂类

@Configuration
public class PhoneConfig {
    @Bean
    public Phone huaweiPhone() {
        return new HuaweiPhone();
    }
    @Bean
    public Phone xiaomiPhone() {
        return new XiaomiPhone();
    }
}

这是企业级项目最常用的优化方案


第九章 避坑指南:工厂方法的常见误区

作为架构师,我总结了新手最容易踩的 5 个坑:

9.1 误区 1:混淆简单工厂和工厂方法

  • 简单工厂:静态方法,一个工厂生产所有产品,违背开闭;
  • 工厂方法:接口 + 子类,一个工厂生产一种产品,遵循开闭。

9.2 误区 2:抽象工厂必须是接口

抽象工厂可以是抽象类,只要定义工厂方法即可,灵活即可。

9.3 误区 3:所有对象都用工厂方法创建

简单对象(无创建逻辑)直接new过度设计会让代码更复杂

9.4 误区 4:工厂方法可以生产多产品

工厂方法仅支持单一产品,多产品族用抽象工厂。

9.5 误区 5:客户端依赖具体工厂

客户端必须用抽象工厂引用具体工厂,否则失去解耦意义。


第十章 架构升华:工厂方法的设计思想与核心价值

10.1 工厂方法的核心思想

面向抽象编程,延迟实例化,解耦创建与使用

它不是单纯的「创建对象」,而是架构设计的解耦思想:将变化的部分(产品实现)封装起来,不变的部分(抽象接口)稳定下来,让系统更灵活、更健壮。

10.2 工厂方法的架构价值

  1. 是企业级代码的基础:所有主流框架(Spring、MyBatis、Dubbo)都基于工厂方法;
  2. 是设计原则的落地载体:完美实践开闭、依赖倒置等核心原则;
  3. 是代码优雅的标准:让代码从「新手级」升级为「架构级」;
  4. 是团队协作的规范:统一对象创建规范,降低沟通成本。

总结(万字核心回顾)

本篇教程从新手痛点→设计原则→简单工厂→工厂方法→源码→实战→优化,由浅入深彻底讲解了工厂方法模式,核心要点总结:

  1. 核心定义:一个产品对应一个专属工厂,抽象工厂定义接口,具体工厂实现创建,延迟实例化;
  2. 四大角色:抽象产品、具体产品、抽象工厂、具体工厂;
  3. 核心优势:完美遵循开闭原则,彻底解耦对象创建与使用,符合七大设计原则;
  4. 适用场景:单一产品、需要扩展、对象创建复杂的企业级项目;
  5. 源码应用:JDK Collection、Spring FactoryBean 都是经典实现;
  6. 优化方案:反射、抽象类、Spring 注解解决类爆炸问题。

工厂方法模式是 Java 设计模式的入门必学、工作必用的核心模式,也是你从编程新手成长为架构师的必经之路。掌握它,你不仅能写出优雅的代码,更能读懂所有主流框架的设计精髓!

posted @ 2026-03-30 23:56  bright_ye  阅读(4)  评论(0)    收藏  举报