工厂模式详解
在软件开发中,工厂模式(Factory Pattern) 是一种常用的创建型设计模式,其核心思想是“封装对象的创建过程”,通过一个统一的“工厂”类来生成目标对象,而非让客户端(调用代码)直接使用 new 关键字创建。这样可以降低客户端与具体产品类的耦合度,提高代码的灵活性、可维护性和可扩展性。
一、为什么需要工厂模式?(解决的核心问题)
在没有工厂模式时,客户端通常直接依赖具体产品类,例如:
// 客户端直接创建具体产品对象,耦合度高
Phone apple = new IPhone();
Phone huawei = new HuaweiPhone();
这种方式存在明显缺陷:
- 耦合度高:客户端必须知道所有具体产品类的存在(如
IPhone、HuaweiPhone),一旦产品类名修改或新增产品,客户端代码需要大量修改。 - 创建逻辑复杂:若对象创建需要复杂的初始化(如配置参数、依赖注入、校验逻辑),这些逻辑会散落在客户端,导致代码冗余且难以维护。
- 扩展性差:新增产品时,需在所有创建对象的地方添加
new语句,违反“开闭原则”(对扩展开放、对修改关闭)。
工厂模式通过引入“工厂”作为中间层,将“对象创建”与“对象使用”分离,完美解决上述问题。
二、工厂模式的3种核心实现形式
根据复杂度和适用场景,工厂模式分为 简单工厂模式、工厂方法模式 和 抽象工厂模式,三者的抽象程度和灵活性依次递增。
1. 简单工厂模式(Simple Factory Pattern)
又称“静态工厂模式”,是工厂模式的基础形式——通过一个单一工厂类,根据客户端传入的“参数”动态创建不同的具体产品对象。
结构组成
|
角色 |
职责描述 |
|
抽象产品(Product) |
定义所有具体产品的公共接口或抽象类(如 |
|
具体产品(Concrete Product) |
实现抽象产品接口的具体类(如 |
|
工厂类(Factory) |
提供静态方法(或实例方法),根据参数判断并创建对应的具体产品对象。 |
代码示例(Java)
// 1. 抽象产品:定义手机的公共行为
interface Phone {
void makeCall(); // 打电话(核心功能)
}
// 2. 具体产品1:iPhone实现
class IPhone implements Phone {
@Override
public void makeCall() {
System.out.println("用iPhone打电话");
}
}
// 2. 具体产品2:华为手机实现
class HuaweiPhone implements Phone {
@Override
public void makeCall() {
System.out.println("用华为手机打电话");
}
}
// 3. 简单工厂类:根据参数创建具体产品
class PhoneFactory {
// 静态方法:接收产品类型参数,返回对应的Phone对象
public static Phone createPhone(String type) {
switch (type) {
case "iPhone":
return new IPhone(); // 创建iPhone
case "Huawei":
return new HuaweiPhone(); // 创建华为手机
default:
throw new IllegalArgumentException("未知的手机类型:" + type);
}
}
}
// 客户端使用:无需直接new具体产品,只需调用工厂
public class Client {
public static void main(String[] args) {
Phone apple = PhoneFactory.createPhone("iPhone");
Phone huawei = PhoneFactory.createPhone("Huawei");
apple.makeCall(); // 输出:用iPhone打电话
huawei.makeCall(); // 输出:用华为手机打电话
}
}
优缺点
- 优点:客户端无需关心产品创建细节,只需传入参数即可获取对象,降低耦合。
- 缺点:工厂类承担了所有产品的创建逻辑,一旦新增产品(如
XiaomiPhone),必须修改工厂类的switch逻辑,违反“开闭原则”,适合产品种类较少且稳定的场景。
2. 工厂方法模式(Factory Method Pattern)
为解决简单工厂模式的“开闭原则”问题,工厂方法模式将“单一工厂”拆分为“多个具体工厂”——每个具体产品对应一个专属的具体工厂,新增产品时只需新增对应的工厂类,无需修改原有代码。
结构组成
|
角色 |
职责描述 |
|
抽象产品(Product) |
同简单工厂,定义具体产品的公共接口(如 |
|
具体产品(Concrete Product) |
同简单工厂,实现抽象产品(如 |
|
抽象工厂(Abstract Factory) |
定义工厂的公共接口,包含一个创建产品的抽象方法(如 |
|
具体工厂(Concrete Factory) |
实现抽象工厂接口,负责创建对应的具体产品(如 |
代码示例(Java)
// 1. 抽象产品:Phone
interface Phone {
void makeCall();
}
// 2. 具体产品:IPhone、HuaweiPhone(同简单工厂)
class IPhone implements Phone {
@Override
public void makeCall() {
System.out.println("用iPhone打电话");
}
}
class HuaweiPhone implements Phone {
@Override
public void makeCall() {
System.out.println("用华为手机打电话");
}
}
// 3. 抽象工厂:定义创建Phone的接口
interface PhoneFactory {
Phone createPhone(); // 抽象方法:创建手机
}
// 4. 具体工厂1:IPhoneFactory(专属创建IPhone)
class IPhoneFactory implements PhoneFactory {
@Override
public Phone createPhone() {
return new IPhone();
}
}
// 4. 具体工厂2:HuaweiFactory(专属创建HuaweiPhone)
class HuaweiFactory implements PhoneFactory {
@Override
public Phone createPhone() {
return new HuaweiPhone();
}
}
// 客户端使用:通过具体工厂获取产品
public class Client {
public static void main(String[] args) {
// 1. 创建对应工厂
PhoneFactory appleFactory = new IPhoneFactory();
PhoneFactory huaweiFactory = new HuaweiFactory();
// 2. 工厂创建产品
Phone apple = appleFactory.createPhone();
Phone huawei = huaweiFactory.createPhone();
apple.makeCall(); // 用iPhone打电话
huawei.makeCall(); // 用华为手机打电话
}
}
新增产品的扩展(符合开闭原则)
若新增 XiaomiPhone,只需两步:
- 新增具体产品类
XiaomiPhone implements Phone; - 新增具体工厂类
XiaomiFactory implements PhoneFactory;
无需修改任何原有代码,完全符合“开闭原则”。
优缺点
- 优点:遵循开闭原则,扩展性强;每个工厂只负责一种产品,职责单一(符合“单一职责原则”)。
- 缺点:产品与工厂一一对应,新增产品时会导致工厂类数量激增(如10种产品对应10个工厂),增加代码复杂度。
3. 抽象工厂模式(Abstract Factory Pattern)
当系统需要创建“一系列相关或相互依赖的产品族”时(而非单一产品),工厂方法模式已无法满足,此时需要抽象工厂模式。例如:手机工厂不仅生产手机(Phone),还生产耳机(Earphone)——IPhone 与 AirPods 是一个产品族,HuaweiPhone 与 HuaweiEarphone 是另一个产品族。
抽象工厂模式的核心是“创建产品族”,而非单一产品。
结构组成
|
角色 |
职责描述 |
|
抽象产品族(Product Family) |
一组相关的抽象产品(如 |
|
具体产品(Concrete Product) |
属于某个产品族的具体实现(如 |
|
抽象工厂(Abstract Factory) |
定义创建“产品族所有成员”的抽象方法(如 |
|
具体工厂(Concrete Factory) |
实现抽象工厂,负责创建“某一产品族”的所有具体产品(如 |
代码示例(Java)
// 1. 抽象产品族1:Phone
interface Phone {
void makeCall();
}
// 1. 抽象产品族2:Earphone
interface Earphone {
void playMusic();
}
// 2. 具体产品(Apple产品族)
class IPhone implements Phone {
@Override
public void makeCall() {
System.out.println("用iPhone打电话");
}
}
class AirPods implements Earphone {
@Override
public void playMusic() {
System.out.println("用AirPods听音乐");
}
}
// 2. 具体产品(Huawei产品族)
class HuaweiPhone implements Phone {
@Override
public void makeCall() {
System.out.println("用华为手机打电话");
}
}
class HuaweiEarphone implements Earphone {
@Override
public void playMusic() {
System.out.println("用华为耳机听音乐");
}
}
// 3. 抽象工厂:定义创建产品族的接口(Phone + Earphone)
interface ElectronicFactory {
Phone createPhone(); // 创建手机
Earphone createEarphone(); // 创建耳机
}
// 4. 具体工厂1:AppleFactory(生产Apple产品族)
class AppleFactory implements ElectronicFactory {
@Override
public Phone createPhone() {
return new IPhone();
}
@Override
public Earphone createEarphone() {
return new AirPods();
}
}
// 4. 具体工厂2:HuaweiFactory(生产Huawei产品族)
class HuaweiFactory implements ElectronicFactory {
@Override
public Phone createPhone() {
return new HuaweiPhone();
}
@Override
public Earphone createEarphone() {
return new HuaweiEarphone();
}
}
// 客户端使用:通过具体工厂获取整个产品族
public class Client {
public static void main(String[] args) {
// 1. 选择Apple产品族工厂
ElectronicFactory appleFactory = new AppleFactory();
Phone applePhone = appleFactory.createPhone();
Earphone appleEarphone = appleFactory.createEarphone();
applePhone.makeCall(); // 用iPhone打电话
appleEarphone.playMusic(); // 用AirPods听音乐
// 2. 选择Huawei产品族工厂
ElectronicFactory huaweiFactory = new HuaweiFactory();
Phone huaweiPhone = huaweiFactory.createPhone();
Earphone huaweiEarphone = huaweiFactory.createEarphone();
huaweiPhone.makeCall(); // 用华为手机打电话
huaweiEarphone.playMusic(); // 用华为耳机听音乐
}
}
优缺点
- 优点:保证同一产品族的产品“一致性”(如
AppleFactory不会生产HuaweiEarphone);新增产品族时只需新增具体工厂,符合开闭原则。 - 缺点:新增“产品族的成员”(如在
ElectronicFactory中新增Tablet平板)时,需修改所有抽象工厂和具体工厂的代码,违反开闭原则(即“产品族稳定,但产品族成员难扩展”)。
三、3种工厂模式的对比与选择
|
维度 |
简单工厂模式 |
工厂方法模式 |
抽象工厂模式 |
|
核心能力 |
单一工厂创建多种产品 |
一个产品对应一个工厂 |
创建“产品族”(多产品组合) |
|
开闭原则 |
违反(新增产品需改工厂) |
符合(新增产品+新增工厂) |
部分符合(新增产品族符合,新增产品成员违反) |
|
代码复杂度 |
低(仅1个工厂) |
中(产品数=工厂数) |
高(需设计产品族和工厂) |
|
适用场景 |
产品少且稳定(如工具类) |
产品多变但独立(如插件) |
需统一产品族(如品牌套件:手机+耳机+平板) |
四、工厂模式的核心价值总结
- 解耦:分离“对象创建”与“对象使用”,客户端无需依赖具体产品类,只需依赖工厂和抽象产品。
- 可维护:对象创建逻辑集中在工厂,修改时只需改工厂,无需改所有客户端。
- 可扩展:新增产品时,简单工厂需修改,工厂方法和抽象工厂只需新增类(符合开闭原则)。
- 一致性:抽象工厂可保证产品族内的产品匹配(如苹果工厂只生产苹果生态产品)。
在实际开发中,工厂模式的思想广泛应用于框架(如 Spring 的 BeanFactory、Java 的 Calendar.getInstance()),是理解“依赖注入”“控制反转”等设计思想的基础。
spring中ioc容器是哪种工厂模式Spring 的 IoC 容器(控制反转容器)融合了多种工厂模式的思想,但其核心设计更接近 抽象工厂模式,同时也包含了简单工厂模式的特性,是一种“增强版”的工厂模式实现。
为什么说 IoC 容器接近抽象工厂模式?
抽象工厂模式的核心是“创建一系列相关或相互依赖的对象”,而 Spring IoC 容器的核心能力正是:
- 管理多种类型的 Bean(对象) 的创建(类似“产品族”);
- 通过统一的接口(如
BeanFactory或ApplicationContext)提供对象的获取,隐藏具体创建细节。
具体对应关系如下:
- 抽象工厂:
BeanFactory接口(定义了获取 Bean 的标准方法,如getBean()); - 具体工厂:
ApplicationContext的实现类(如ClassPathXmlApplicationContext、AnnotationConfigApplicationContext等,负责实际创建和管理 Bean); - 抽象产品:各种 Bean 的接口或父类;
- 具体产品:容器中管理的具体对象(如
UserService、OrderDao等)。
同时包含简单工厂模式的特性
Spring IoC 容器也具备简单工厂模式的特点:
- 通过一个统一的入口(
getBean()方法) 创建不同类型的对象,客户端只需指定 Bean 的名称或类型(类似“参数”),无需关心具体创建逻辑; - 例如
context.getBean("userService")或context.getBean(UserService.class),容器内部根据配置(XML/注解)动态创建对应的对象。
与传统工厂模式的区别
Spring IoC 容器并非严格遵循某一种经典工厂模式,而是进行了扩展:
- 动态配置:传统工厂模式的产品创建逻辑硬编码在工厂类中,而 Spring 通过配置文件(XML)或注解(
@Component、@Bean等)动态定义 Bean 的创建规则,灵活性更高; - 生命周期管理:IoC 容器不仅创建对象,还负责对象的初始化、依赖注入、销毁等全生命周期管理,这是传统工厂模式不具备的;
- 依赖注入(DI):容器会自动处理 Bean 之间的依赖关系(如
@Autowired),而传统工厂模式需要手动在工厂中管理依赖。
总结
Spring IoC 容器的设计思想以 抽象工厂模式 为基础(管理多种对象的创建,通过统一接口提供服务),同时吸收了简单工厂模式的便捷性(通过单一入口创建对象),并结合 IoC/DI 思想进行了增强,是一种更灵活、更强大的“超级工厂”实现。
更多推荐



所有评论(0)