工厂模式
约 2158 字大约 7 分钟
理论设计模式
2026-04-06
工厂模式(Factory Pattern)是 Java 开发中最高频使用的设计模式之一,属于创建型模式。它的核心思想非常直观:将对象的创建逻辑与使用逻辑分离,通过引入“工厂”这一中间层来封装实例化过程,避免在代码中直接使用 new 关键字。
这种模式虽然结构简单,但在降低代码耦合度、提升系统可维护性和扩展性方面作用巨大。
为什么我们需要工厂模式?
在传统的开发中,如果我们直接通过 new 关键字创建对象,往往会面临以下痛点:
- 耦合度高:使用方(客户端)必须了解对象的具体创建细节(如构造参数、依赖关系)。一旦对象的创建逻辑发生变化(例如增加了构造参数),所有使用该对象的地方都需要同步修改。
- 代码冗余:如果在多个地方创建同一个类型的对象,创建逻辑会被重复编写,违反了“单一职责原则”。
- 扩展性差:当需要新增一种对象时,往往需要在所有使用处添加
if-else或switch-case判断,这严重违反了“开闭原则”(对扩展开放,对修改关闭)。
工厂模式通过引入工厂类作为中间层,让客户端只依赖工厂接口,无需关心对象是如何被创建的,从而实现了解耦、复用和易扩展。
工厂模式家族主要包含三种形态:简单工厂模式、工厂方法模式和抽象工厂模式。
简单工厂模式
简单工厂模式(Simple Factory),也称为静态工厂方法模式。它由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类的实例。
核心逻辑
- 工厂角色:核心部分,负责实现创建所有实例的内部逻辑。通常包含一个静态方法,根据参数(如字符串、枚举)通过
if-else或switch判断来返回不同的产品对象。 - 抽象产品角色:所有具体产品类的父类或接口,负责描述产品的公共行为。
- 具体产品角色:实现了抽象产品接口的具体类,是工厂创建的目标。
实战案例:手机生产工厂 假设我们有一个手机接口,以及华为和小米两个具体实现。
定义产品接口与实现
// 抽象产品 public interface Phone { String callUp(); } // 具体产品 A public class HuaWeiPhoneImpl implements Phone { private Integer cpuCount; public HuaWeiPhoneImpl(Integer cpuCount) { this.cpuCount = cpuCount; } @Override public String callUp() { return "华为手机打电话(CPU:" + cpuCount + "核)"; } } // 具体产品 B public class XiaoMiPhoneImpl implements Phone { private Integer cpuCount; public XiaoMiPhoneImpl(Integer cpuCount) { this.cpuCount = cpuCount; } @Override public String callUp() { return "小米手机打电话(CPU:" + cpuCount + "核)"; } }定义简单工厂类
public class PhoneFactory { // 静态方法,根据类型创建手机 public static Phone createPhone(String brand) { Phone phone = null; if ("HUAWEI".equals(brand)) { phone = new HuaWeiPhoneImpl(8); } else if ("XIAOMI".equals(brand)) { phone = new XiaoMiPhoneImpl(8); } else { throw new IllegalArgumentException("不支持的品牌"); } return phone; } }客户端调用
public class Client { public static void main(String[] args) { // 客户端只需传入参数,无需关心具体类的实例化 Phone phone = PhoneFactory.createPhone("HUAWEI"); System.out.println(phone.callUp()); } }
优缺点分析
- 优点:客户端与具体产品解耦,只需记住参数即可获取对象;工厂类集中管理创建逻辑,便于维护。
- 缺点:违反开闭原则。如果需要新增一种手机品牌(例如 OPPO),必须修改
PhoneFactory类的createPhone方法,增加新的判断逻辑。当产品种类繁多时,工厂类的逻辑会变得非常臃肿,难以维护。
工厂方法模式
为了解决简单工厂模式违反开闭原则的问题,工厂方法模式(Factory Method Pattern)应运而生。
核心逻辑
- 不再由一个工厂类生产所有产品,而是定义一个创建产品的抽象接口。
- 让子类(具体工厂)决定实例化哪一个类。
- 一个产品对应一个工厂。当需要新增产品时,只需新增对应的工厂类,无需修改现有的工厂代码。
实战案例:品牌专属工厂 我们将工厂也抽象化,每个手机品牌都有自己专属的工厂。
定义工厂接口
public interface PhoneFactory { Phone createPhone(); }定义具体工厂
// 华为手机工厂 public class HuaWeiPhoneFactory implements PhoneFactory { @Override public Phone createPhone() { return new HuaWeiPhoneImpl(8); } } // 小米手机工厂 public class XiaoMiPhoneFactory implements PhoneFactory { @Override public Phone createPhone() { return new XiaoMiPhoneImpl(8); } }客户端调用
public class Client { public static void main(String[] args) { // 使用哪个工厂,就生产哪个品牌的产品 PhoneFactory factory = new HuaWeiPhoneFactory(); Phone phone = factory.createPhone(); System.out.println(phone.callUp()); } }
优缺点分析
- 优点:完全符合开闭原则。新增产品时,只需增加一个新的具体工厂类和产品类,无需修改任何现有代码。
- 缺点:类的数量会成倍增加(每个产品对应一个工厂),增加了系统的复杂度和一定的运行开销。
抽象工厂模式
工厂方法模式针对的是单一产品等级结构(例如只生产手机)。但在实际业务中,我们往往需要生产一系列相关的产品(例如一个品牌既生产手机,又生产路由器)。这时就需要用到抽象工厂模式(Abstract Factory Pattern)。
核心逻辑
- 抽象工厂模式是工厂方法模式的升级,它针对的是产品族。
- 一个具体的工厂可以生产多个不同种类但属于同一品牌的产品。
- 客户端通过抽象工厂接口获取一系列相关的产品,而无需指定它们的具体类。
实战案例:品牌产品族工厂 假设我们要生产“华为全家桶”(手机 + 路由器)和“小米全家桶”(手机 + 路由器)。
定义多个产品接口
public interface Phone { void callUp(); } public interface Router { void openWifi(); }定义抽象工厂
public interface DeviceFactory { Phone createPhone(); // 生产手机 Router createRouter(); // 生产路由器 }定义具体工厂(产品族)
// 华为工厂:生产华为手机和华为路由器 public class HuaweiFactory implements DeviceFactory { @Override public Phone createPhone() { return new HuaWeiPhoneImpl(); } @Override public Router createRouter() { return new HuaweiRouterImpl(); } } // 小米工厂:生产小米手机和小米路由器 public class XiaomiFactory implements DeviceFactory { @Override public Phone createPhone() { return new XiaoMiPhoneImpl(); } @Override public Router createRouter() { return new XiaoMiRouterImpl(); } }客户端调用
public class Client { public static void main(String[] args) { // 获取一个华为工厂 DeviceFactory factory = new HuaweiFactory(); // 该工厂生产的一系列产品都是华为品牌的,保证了兼容性 Phone phone = factory.createPhone(); Router router = factory.createRouter(); phone.callUp(); router.openWifi(); } }
优缺点分析
- 优点:隔离了具体类的生成,客户端不需要知道具体类名;保证了产品族的一致性(不会出现华为手机配小米路由器的情况);增加新的产品族(例如新增“苹果工厂”)非常容易。
- 缺点:难以扩展产品种类。如果需要在工厂中增加一种新产品(例如“智能手表”),那么必须修改抽象工厂接口以及所有具体工厂类,这违反了开闭原则。
三种模式的对比与选型
| 模式 | 核心特点 | 适用场景 | 扩展性 |
|---|---|---|---|
| 简单工厂 | 一个工厂生产所有产品,通过参数区分 | 业务逻辑简单,产品种类固定且较少 | 扩展新产品需修改工厂代码 |
| 工厂方法 | 一个工厂只生产一种产品 | 产品种类经常增加,且不需要维护产品族 | 扩展新产品无需修改代码,符合开闭原则 |
| 抽象工厂 | 一个工厂生产一族相关产品 | 需要保证产品之间的关联性和兼容性(如跨平台UI组件) | 扩展新产品族容易,扩展新产品种类困难 |
总结
工厂模式是构建灵活、可扩展系统的重要基石。
- 如果你只是想简单封装对象创建过程,简单工厂足矣。
- 如果你希望系统符合开闭原则,且产品之间没有强关联,选择工厂方法。
- 如果你需要创建一系列相互关联、依赖的产品对象(产品族),抽象工厂是最佳选择。
在实际的框架开发(如 Spring、MyBatis)中,这些模式往往被组合使用,以实现高度的解耦和配置化。
