原型模式
引言
原型模式是一种创建型设计模式,其核心在于通过复制现有对象来创建新对象,无需依赖复杂的构造函数或初始化逻辑。它利用“克隆”思想,让对象能够自我复制,特别适合创建成本高或配置复杂的对象。原型模式强调高效与灵活,仿佛为对象赋予了“分裂术”,使创建过程既快速又可控。
实际开发中的用途
在实际开发中,原型模式常用于需要频繁创建相似对象的场景,如配置对象、模板实例或复杂数据结构的复制。它避免了重复的初始化开销,特别适合高并发环境或对象构造复杂的情况。例如,在报表系统中,基于模板快速生成多份报表副本,或在游戏开发中复制敌人实例,都能显著提升性能。原型模式通过复制解耦了对象创建与客户端代码,增强了系统的可扩展性。
开发中的示例
设想一个文档管理系统,用户需要基于模板快速生成多份合同文档。每份合同内容相似,但部分字段(如客户名)不同。通过原型模式,可定义一个合同模板对象,客户端只需克隆模板并修改特定字段即可生成新合同。这种方式避免了重复构造复杂对象,提高了效率,同时保持模板一致性。
Spring 源码中的应用
Spring 框架中,原型模式在 Bean 作用域(prototype
作用域)的实现中体现得淋漓尽致。当 Bean 定义为 prototype
作用域时,Spring 容器每次请求该 Bean 都会创建一个全新实例,类似于通过原型克隆生成新对象。这种机制由 AbstractBeanFactory
的 doGetBean
方法及相关创建逻辑实现,确保每次返回的 Bean 都是独立的,客户端无需关心底层构造细节。
以下是 Spring 源码的典型片段(AbstractBeanFactory.java
):
// Spring 框架中的 AbstractBeanFactory
protected <T> T doGetBean(
String name, Class<T> requiredType, Object[] args, boolean typeCheckOnly) throws BeansException {
// 获取规范化 Bean 名称并检查别名
String beanName = transformedBeanName(name);
Object beanInstance;
// 检查是否存在单例实例(prototype 作用域不会缓存)
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
} else {
// 获取 Bean 定义
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// 检查是否为 prototype 作用域
if (mbd.isPrototype()) {
// 创建新的原型 Bean 实例
Object prototypeInstance = null;
try {
// 前置处理,记录原型创建状态
beforePrototypeCreation(beanName);
// 创建 Bean 实例,调用 createBean 方法
prototypeInstance = createBean(beanName, mbd, args);
} finally {
// 后置处理,清理原型创建状态
afterPrototypeCreation(beanName);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
} else {
// 单例或其他作用域的处理逻辑
// ...
}
}
return (T) beanInstance;
}
这段代码展示了 Spring 如何通过原型模式实现 prototype
作用域的 Bean 创建。详细分析如下:
- 原型模式的体现:
- 当 Spring 检测到 Bean 为
prototype
作用域(mbd.isPrototype()
),它不会从单例缓存中获取实例,而是通过createBean
方法生成全新实例。这与原型模式的核心思想一致:通过“复制”或“新建”生成独立对象,而非复用已有对象。 createBean
方法(定义在AbstractAutowireCapableBeanFactory
中)负责实例化 Bean,包括调用构造函数、处理依赖注入和执行初始化回调。每次调用生成新对象,类似于原型模式的“克隆”过程。
- 当 Spring 检测到 Bean 为
- 关键方法解析:
beforePrototypeCreation(beanName)
和afterPrototypeCreation(beanName)
是原型模式生命周期管理的关键。它们记录当前正在创建的原型 Bean,防止高并发场景下的重复创建或状态混乱。createBean
方法内部调用doCreateBean
,完成实例化、属性填充和初始化,确保新生成的 Bean 完全独立,符合原型模式要求。
- 解耦与扩展性:
- 原型模式在 Spring 中解耦了客户端与 Bean 创建过程。客户端只需通过
getBean
方法请求 Bean,无需了解构造逻辑或依赖关系。 - Spring 的 IoC 容器通过
BeanDefinition
存储原型模板的元信息,每次创建时基于模板生成新实例,支持动态扩展,如通过配置文件或注解调整 Bean 属性,无需修改客户端代码。
- 原型模式在 Spring 中解耦了客户端与 Bean 创建过程。客户端只需通过
- 实际问题解决:
- 原型模式解决了单例作用域无法满足的场景,如需要独立状态的对象(例如用户会话数据或临时配置)。通过
prototype
作用域,Spring 确保每个 Bean 实例互不干扰,适合高动态性需求。 - 它还降低了复杂对象创建的性能开销。Spring 通过
BeanDefinition
缓存模板信息,避免重复解析配置,仅在需要时生成新实例。
- 原型模式解决了单例作用域无法满足的场景,如需要独立状态的对象(例如用户会话数据或临时配置)。通过
这种实现使 Spring 的原型模式高效且灵活,广泛应用于需要动态生成对象的场景,如测试环境中的 mock 对象或多租户系统中的独立配置。
代码案例
以下是一个完整的、独立的 Java 代码案例,模拟一个图形编辑器场景,通过原型模式克隆图形对象。编辑器需要生成多个相似但位置或颜色不同的矩形图形,通过克隆原型模板高效创建新图形,清晰体现原型模式的“克隆”特性。
// 图形接口,支持克隆
public interface Shape {
void setPosition(int x, int y);
void setColor(String color);
void draw();
Shape cloneShape();
}
// 具体图形实现 - 矩形
public class Rectangle implements Shape, Cloneable {
private int x;
private int y;
private String color;
private int width; // 模拟复杂配置
private int height; // 模拟复杂配置
private String borderStyle; // 模拟复杂配置
public Rectangle() {
// 模拟复杂初始化过程
this.width = 100;
this.height = 50;
this.borderStyle = "Solid";
this.color = "Black";
this.x = 0;
this.y = 0;
}
@Override
public void setPosition(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public void setColor(String color) {
this.color = color;
}
@Override
public void draw() {
System.out.println("绘制矩形: 位置=(" + x + ", " + y + "), 颜色=" + color +
", 宽度=" + width + ", 高度=" + height + ", 边框样式=" + borderStyle);
}
@Override
public Shape cloneShape() {
try {
return (Rectangle) super.clone(); // 浅克隆,适用于此场景
} catch (CloneNotSupportedException e) {
throw new RuntimeException("克隆失败", e);
}
}
}
// 原型管理器
public class ShapePrototypeManager {
private Shape prototype;
public ShapePrototypeManager(Shape prototype) {
this.prototype = prototype;
}
public Shape createShape() {
return prototype.cloneShape();
}
}
// 主程序
public class GraphicsEditor {
public static void main(String[] args) {
// 创建矩形原型
Shape rectanglePrototype = new Rectangle();
// 使用原型管理器
ShapePrototypeManager manager = new ShapePrototypeManager(rectanglePrototype);
// 克隆生成矩形1
Shape shape1 = manager.createShape();
shape1.setPosition(10, 20);
shape1.setColor("Red");
shape1.draw();
// 克隆生成矩形2
Shape shape2 = manager.createShape();
shape2.setPosition(50, 60);
shape2.setColor("Blue");
shape2.draw();
// 克隆生成矩形3
Shape shape3 = manager.createShape();
shape3.setPosition(100, 120);
shape3.draw();
}
}
此 Java 示例通过图形编辑器场景清晰展示了原型模式。Rectangle
类实现了 Shape
接口和 Cloneable
,通过 cloneShape
方法使用 Java 的 clone()
实现浅克隆(适用于此简单场景)。构造函数模拟了复杂初始化过程,设置了 width
、height
和 borderStyle
等属性。ShapePrototypeManager
管理原型模板并提供克隆方法,解耦了客户端与克隆过程。在 GraphicsEditor
主程序中,通过克隆原型创建多个矩形图形,仅修改位置和颜色,避免了重复的复杂初始化。
运行代码将输出:
绘制矩形: 位置=(10, 20), 颜色=Red, 宽度=100, 高度=50, 边框样式=Solid
绘制矩形: 位置=(50, 60), 颜色=Blue, 宽度=100, 高度=50, 边框样式=Solid
绘制矩形: 位置=(100, 120), 颜色=Black, 宽度=100, 高度=50, 边框样式=Solid
原型模式在此通过克隆原型高效生成相似对象,保留复杂配置(如 width
、height
、borderStyle
),仅需定制动态属性(如位置、颜色)。此案例直观、独立,完美体现了原型模式降低创建开销、提升灵活性的优势,适用于需要快速生成相似对象的场景。
总结
原型模式如同一台高效的“对象复印机”,通过克隆现有对象大幅降低创建成本,赋予系统无与伦比的灵活性。在 Spring 中,prototype
作用域将原型模式融入 IoC 核心,通过 AbstractBeanFactory
的精细实现,确保每次请求生成独立实例,完美支持动态对象生成。在实际开发中,原型模式通过克隆模板应对复杂对象创建的性能挑战,让代码如行云流水般优雅。掌握原型模式,不仅能优化性能,更能实现“一次定义,无限复制”的开发哲学。
(对您有帮助 && 觉得我总结的还行) -> 受累点个免费的赞👍,谢谢