抽象工厂 vs 原型模式:核心区别与原型模式实战解析

抽象工厂 vs 原型模式:核心区别与原型模式实战解析

在 GoF 设计模式中,抽象工厂(Abstract Factory)原型模式(Prototype) 都属于创建型模式。很多开发者容易混淆它们,尤其听到"原型工厂"这样的非标准术语时更是一头雾水。本文将从定义、类图、代码示例、使用场景等多个维度深度剖析两者的区别,并重点讲解原型模式(Prototype Pattern)的核心思想、浅克隆与深克隆、以及它在 Spring、JDK 等框架中的实际应用。


一、快速理解:抽象工厂 vs 原型模式

维度 抽象工厂模式 原型模式
目的 创建一系列相关或相互依赖的对象族 通过复制(克隆) 现有实例来创建新对象
核心操作 定义工厂接口,每个具体工厂负责生成一族产品 定义 clone() 方法,通过拷贝原型对象来创建新实例
关键角色 AbstractFactory、ConcreteFactory、AbstractProduct、ConcreteProduct Prototype、ConcretePrototype、Client
典型应用 跨平台 UI 控件(Win/Mac 风格)、数据库连接工厂 Spring 原型作用域、Java 对象克隆、缓存对象复制
优点 隔离具体产品类,保证产品族一致性 减少子类化,动态配置对象结构
缺点 新增产品族麻烦(需改抽象工厂) 深克隆需谨慎处理循环引用

⚠️ 注意:没有"原型工厂"这个标准模式名称,通常指 原型模式(Prototype Pattern)。本文统一称为"原型模式"。


二、抽象工厂模式详解

2.1 定义与场景

抽象工厂提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。例如:生产一套"现代风格"的沙发、茶几、椅子,或者"维多利亚风格"的一套家具。

2.2 类图

<<interface>>
AbstractFactory
+createProductA() : AbstractProductA
+createProductB() : AbstractProductB
ConcreteFactory1
+createProductA() : ProductA1
+createProductB() : ProductB1
ConcreteFactory2
+createProductA() : ProductA2
+createProductB() : ProductB2
<<interface>>
AbstractProductA
<<interface>>
AbstractProductB
ProductA1
ProductA2
ProductB1
ProductB2

2.3 代码示例(Java)

java 复制代码
// 产品接口
interface Button { void paint(); }
interface Checkbox { void check(); }

// 具体产品(Win风格)
class WinButton implements Button {
    public void paint() { System.out.println("Windows Button"); }
}
class WinCheckbox implements Checkbox {
    public void check() { System.out.println("Windows Checkbox"); }
}

// 具体产品(Mac风格)
class MacButton implements Button {
    public void paint() { System.out.println("Mac Button"); }
}
class MacCheckbox implements Checkbox {
    public void check() { System.out.println("Mac Checkbox"); }
}

// 抽象工厂
interface GUIFactory {
    Button createButton();
    Checkbox createCheckbox();
}

// 具体工厂
class WinFactory implements GUIFactory {
    public Button createButton() { return new WinButton(); }
    public Checkbox createCheckbox() { return new WinCheckbox(); }
}
class MacFactory implements GUIFactory {
    public Button createButton() { return new MacButton(); }
    public Checkbox createCheckbox() { return new MacCheckbox(); }
}

// 客户端
public class Client {
    private Button button;
    private Checkbox checkbox;
    public Client(GUIFactory factory) {
        button = factory.createButton();
        checkbox = factory.createCheckbox();
    }
    public void paint() {
        button.paint();
        checkbox.check();
    }
}

2.4 适用场景

  • 系统需要独立于产品的创建、组合和表示。
  • 需要保证一个产品族内的对象一起工作(比如 Win 风格的所有控件)。
  • 你可能只使用一个产品族,但将来可能切换为另一族。

三、原型模式(Prototype Pattern)详解

3.1 定义与核心思想

用原型实例指定创建对象的种类,并且通过复制(克隆) 这些原型来创建新的对象。

原型模式的核心是克隆 ,而不是调用 new 来创建对象。当创建对象的成本较高(如涉及网络、数据库、复杂计算),且对象之间只有少量状态不同时,克隆可以极大提升性能。

3.2 浅克隆与深克隆

  • 浅克隆 :复制基本类型和引用类型的地址,即原对象和克隆对象共享引用类型的实例。
  • 深克隆:递归复制引用类型内部的所有对象,实现完全独立的副本。

Java 中实现克隆需要:

  • 实现 Cloneable 接口(标记接口)。
  • 重写 clone() 方法,通常调用 super.clone()(浅克隆)。若要深克隆,需手动克隆引用成员。

3.3 类图

<<interface>>
Prototype
+clone() : Prototype
ConcretePrototype1
-String field
-List<String> list
+clone() : ConcretePrototype1
ConcretePrototype2
-int value
+clone() : ConcretePrototype2
Client
+operation()

3.4 代码示例(Java + 深克隆)

java 复制代码
// 原型接口
public interface Prototype {
    Prototype clone();  // 或者使用 Object 的 clone()
}

// 具体原型类
public class ShoppingCart implements Prototype, Cloneable {
    private Long userId;
    private List<Item> items;  // 引用类型,需深克隆
    
    public ShoppingCart(Long userId, List<Item> items) {
        this.userId = userId;
        this.items = items;
    }
    
    @Override
    public ShoppingCart clone() {
        try {
            ShoppingCart clone = (ShoppingCart) super.clone(); // 浅克隆
            // 手动深克隆 items
            clone.items = new ArrayList<>(this.items);
            // 如果 Item 也是引用类型,同样需要递归克隆
            return clone;
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }
    
    // getters/setters...
}

// 客户端克隆购物车
ShoppingCart original = new ShoppingCart(100L, itemList);
ShoppingCart copy = original.clone();
copy.setUserId(101L);  // 新用户获得相同购物车内容,但独立修改不影响原对象

3.5 实际应用场景(你在哪里用到过?)

① Spring Framework 中的原型作用域

Spring 的 Bean 有 Singleton (默认)和 Prototype 作用域。当 Bean 配置为 scope="prototype" 时,每次请求该 Bean 都会通过克隆或新建 返回一个新的实例。虽然 Spring 内部不是直接使用 Java 的 clone(),但思想完全一致:通过原型定义创建新对象

java 复制代码
@Component
@Scope("prototype")
public class OrderProcessor {
    // 每次注入都会是新实例
}
② JDK 中的 Object.clone()Cloneable

Java 语言内置支持原型模式,java.lang.Object 提供了 protected native Object clone() 方法,任何实现了 Cloneable 接口的类都可以调用 super.clone() 获得浅拷贝。例如 ArrayListHashMap 都实现了 clone()

③ 缓存对象复制

在高并发场景下,某些配置数据(如商品类目树)从 DB 加载后可以被复制给多个请求线程,每个线程可以独立修改副本而不影响原缓存。

④ 游戏开发中的角色复制

比如"分身术"技能:基于玩家当前角色状态(装备、血量等)克隆出一个完全相同的新角色对象。

⑤ 性能优化:避免重复数据库查询

一个复杂报表查询耗时 5 秒,得到结果后将其原型化。后续相同参数的请求直接克隆原型对象返回,无需再查 DB。


四、抽象工厂 vs 原型模式:对比总结

对比点 抽象工厂 原型模式
创建方式 通过工厂接口的 createXXX() 方法创建新对象(通常是 new 通过现有对象的 clone() 方法复制对象
对象状态 创建的对象是全新的、通常具有默认状态 克隆出来的对象与原型对象初始状态完全相同,之后可独立修改
复杂度 需要设计产品等级结构和工厂层次 需要处理浅/深克隆及循环引用
对客户透明 客户不知道具体产品类 客户只需要知道原型接口
性能 第一次创建时较慢(需调用构造器) 克隆通常比 new + 属性赋值快(尤其构造器有复杂逻辑时)
扩展方向 增加新产品族(新的具体工厂) 增加新原型类(实现 clone

两者并不互斥,甚至可结合使用

例如,抽象工厂可以产生不同的原型对象,然后客户端通过克隆这些原型来创建产品族中的具体产品。这样抽象工厂负责"选取"原型,原型模式负责"复制"实例。


五、选择流程图:抽象工厂还是原型模式?





需要创建对象
创建对象的成本很高

(网络/IO/复杂计算)?
原型模式更合适
需要创建一系列

相互关联的对象?
抽象工厂模式
简单工厂或工厂方法
确保对象支持克隆

处理深拷贝问题
设计产品族接口

和具体工厂


六、常见面试题

Q1:原型模式是工厂模式的一种吗?

A:不是。原型模式属于创建型模式,但不属于工厂模式。它不依赖工厂,而是依赖克隆。

Q2:Java 的 clone() 为什么是浅克隆?如何实现深克隆?

A:Object.clone() 是浅克隆,因为它只复制成员字段的值(引用类型只复制地址)。深克隆需要手动复制引用类型内部的对象,常用的方式有:

  • 递归调用 clone()(要求所有引用类都实现 Cloneable)。
  • 使用序列化(Serializable + 流复制)。

Q3:原型模式和单例模式冲突吗?

A:单例模式只允许一个实例,原型模式每次克隆产生新实例,两者目标相反,不能同时应用在一个类上。

Q4:Spring 的 prototype 作用域是每次都是全新对象还是克隆?

A:Spring 默认使用反射调用构造器创建新实例,而不是 clone。但概念上属于"原型模式"思想:每次获取都是不同的对象实例。


七、总结

  • 抽象工厂:解决"产品族"创建问题,强调产品间的关联性。
  • 原型模式:解决"昂贵创建"问题,通过克隆简化对象创建。

在实际开发中,如果对象的创建成本主要来自构造器中的复杂逻辑(如大量计算、数据库查询),原型模式可以显著提升性能;如果需要保证不同操作系统下的 UI 控件风格一致,抽象工厂是最佳选择。

相关推荐
之歆2 小时前
DAY_25 JavaScript 原型、原型链与值类型/引用类型 ── 深度全解(上)
开发语言·javascript·原型模式
少许极端3 天前
AI修炼记3-RAG
人工智能·ai·原型模式·rag
c++之路3 天前
原型模式(Prototype Pattern)
原型模式
栉甜4 天前
Js进阶(4)
开发语言·javascript·原型模式
UXbot5 天前
AI画原型工具如何帮非设计师快速生成UI界面
前端·vue.js·ui·kotlin·swift·原型模式·web app
UXbot5 天前
2026年文字转原型AI工具推荐:输入一句需求描述,自动生成多页面可交互界面
前端·低代码·ui·交互·ai编程·原型模式
UXbot5 天前
AI应用原型平台核心能力:界面自动生成、交互流程编辑、多格式代码导出详解
前端·低代码·交互·软件构建·原型模式·web app
蜡笔小马6 天前
03.C++设计模式-原型模式
c++·设计模式·原型模式
宁雨桥9 天前
前端修行日记之JS 原型与 AI基础常识
前端·javascript·原型模式