目录
[2、浅拷贝 vs 深拷贝](#2、浅拷贝 vs 深拷贝)
[1、手动 clone 引用成员](#1、手动 clone 引用成员)
前言
原型模式属于创建型模式。用于创建重复的对象,同时又能保证性能。要求原型对象实现一个"克隆"自身的方法,通过调用这个方法来创建一个新的实例对象。

1、原型模式
1.1、定义
通过复制(克隆)已有对象来创建新对象,而不是通过 new 构造函数来创建。原型对象保存了实例的初始状态,客户端通过克隆原型得到新的对象。
如下图所示:

1.2、使用场景
什么时候用原型模式更合适?
1、对象创建成本高(比如大量属性赋值、复杂初始化);
2、需要运行时决定要创建哪种具体类实例;
3、需要大量相似对象(使用原型复制比重复 new 和初始化更高效)。
1.3、与bean的区别
1、原型模式(Prototype Pattern):
一种"创建型设计模式",通过复制(克隆)已有对象来创建新对象,关注如何复制对象(clone / 拷贝构造 / 序列化等)。
通常靠对象自身实现复制逻辑(Object.clone、copy constructor、序列化等)。
2、Spring 的 prototype scope:
Spring 容器中一个"作用域/生命周期策略",表示每次从容器获取该 bean 都会创建一个新的实例,关注的是容器如何管理 bean 的生命周期。
由容器负责新建(调用构造器/工厂方法并做依赖注入),并不要求对象实现 clone。
2、浅拷贝 vs 深拷贝
2.1、分类
1、浅拷贝
复制对象本身,但对象内部的引用类型字段(比如其他对象、集合)只是复制引用,仍然指向同一个子对象。
换句话说,"复制的是外壳,里面的东西是共享的"。
⚠️注意:
如果原型对象的成员变量是值类型(byte,short,int,long,char,double,float,boolean).那么就直接复制;如果是复杂的类型,(如枚举、对象)就只复制对应的内存地址。
2、深拷贝
不仅复制对象本身,也递归复制它引用的所有可变子对象,得到真正独立的完整副本。
换句话说,"里面的东西也全部复制了一份"。
2.2、实现方式
实现方式概述
- 使用 Cloneable + Object.clone()(容易实现浅拷贝,做深拷贝需手动 clone 引用字段)
- 使用拷贝构造函数(推荐:明确、可控)
- 使用序列化(Serializable)深拷贝(简便但开销高)
- 使用原型注册表(Registry)统一管理可克隆原型
1:浅拷贝(使用 Cloneable、super.clone())
java
// Address.java
class Address implements Cloneable {
String city;
Address(String city) { this.city = city; }
@Override
public Address clone() {
try {
return (Address) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
@Override
public String toString() { return "Address{city='" + city + "'}"; }
}
// PersonShallow.java
class PersonShallow implements Cloneable {
String name;
int age;
Address address; // 引用类型
PersonShallow(String name, int age, Address address) {
this.name = name; this.age = age; this.address = address;
}
@Override
public PersonShallow clone() {
try {
// super.clone() 做的是浅拷贝:基本类型复制,引用复制引用
return (PersonShallow) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
@Override
public String toString() {
return "PersonShallow{name='" + name + "', age=" + age + ", address=" + address + "}";
}
}
// MainShallowDemo.java
public class MainShallowDemo {
public static void main(String[] args) {
Address addr = new Address("Beijing");
PersonShallow p1 = new PersonShallow("Alice", 30, addr);
PersonShallow p2 = p1.clone();
System.out.println("Before change:");
System.out.println("p1 = " + p1);
System.out.println("p2 = " + p2);
// 修改 p2 的 address,会影响 p1(因为浅拷贝共享同一个 Address)
p2.address.city = "Shanghai";
System.out.println("After change:");
System.out.println("p1 = " + p1);
System.out.println("p2 = " + p2);
}
}
修改克隆对象中引用类型会影响原对象。
2:深拷贝(clone 内部手动 clone 引用成员或使用序列化)
1、手动 clone 引用成员
(建议)
java
// PersonDeep.java
class PersonDeep implements Cloneable {
String name;
int age;
Address address;
PersonDeep(String name, int age, Address address) {
this.name = name; this.age = age; this.address = address;
}
@Override
public PersonDeep clone() {
try {
PersonDeep copy = (PersonDeep) super.clone();
// 手动深拷贝引用对象
copy.address = this.address.clone();
return copy;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
@Override
public String toString() {
return "PersonDeep{name='" + name + "', age=" + age + ", address=" + address + "}";
}
}
// MainDeepDemo.java
public class MainDeepDemo {
public static void main(String[] args) {
Address addr = new Address("Beijing");
PersonDeep p1 = new PersonDeep("Bob", 40, addr);
PersonDeep p2 = p1.clone();
System.out.println("Before change:");
System.out.println("p1 = " + p1);
System.out.println("p2 = " + p2);
p2.address.city = "Guangzhou"; // 不会影响 p1
System.out.println("After change:");
System.out.println("p1 = " + p1);
System.out.println("p2 = " + p2);
}
}
2、序列化做深拷贝
(可用于任意深度,但性能/可读性较差)
java
import java.io.*;
// 使用可序列化的类
class AddressS implements Serializable {
String city;
AddressS(String city) { this.city = city; }
public String toString() { return "AddressS{city='" + city + "'}"; }
}
class PersonS implements Serializable {
String name;
int age;
AddressS address;
PersonS(String name, int age, AddressS address) {
this.name = name; this.age = age; this.address = address;
}
public String toString() { return "PersonS{name='" + name + "', age=" + age + ", address=" + address + "}"; }
}
public class SerializeDeepCopy {
@SuppressWarnings("unchecked")
public static <T extends Serializable> T deepCopy(T obj) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bos);
out.writeObject(obj);
out.flush();
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream in = new ObjectInputStream(bis);
return (T) in.readObject();
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
PersonS p1 = new PersonS("Cathy", 28, new AddressS("Shenzhen"));
PersonS p2 = deepCopy(p1);
p2.address.city = "Hangzhou";
System.out.println("p1 = " + p1);
System.out.println("p2 = " + p2);
}
}
3、原型注册表
java
import java.util.*;
// 简单的 Prototype 接口(返回 Object 或 Prototype 的 clone)
interface Prototype {
Prototype clone();
}
// 一个具体原型
class ConcretePrototype implements Prototype {
private String id;
private Map<String, String> data = new HashMap<>();
ConcretePrototype(String id) { this.id = id; }
void put(String k, String v) { data.put(k, v); }
String get(String k) { return data.get(k); }
@Override
public Prototype clone() {
// 简单示例做浅拷贝 + 拷贝集合内容以避免共享
ConcretePrototype copy = new ConcretePrototype(this.id);
copy.data = new HashMap<>(this.data);
return copy;
}
@Override
public String toString() {
return "ConcretePrototype{id='" + id + "', data=" + data + "}";
}
}
class PrototypeRegistry {
private Map<String, Prototype> registry = new HashMap<>();
void register(String key, Prototype prototype) { registry.put(key, prototype); }
Prototype create(String key) {
Prototype p = registry.get(key);
return (p != null) ? p.clone() : null;
}
}
// Usage
public class PrototypeRegistryDemo {
public static void main(String[] args) {
PrototypeRegistry reg = new PrototypeRegistry();
ConcretePrototype protoA = new ConcretePrototype("A");
protoA.put("name", "TemplateA");
reg.register("A", protoA);
ConcretePrototype instance = (ConcretePrototype) reg.create("A");
instance.put("name", "InstanceFromA");
System.out.println("protoA = " + protoA);
System.out.println("instance = " + instance);
}
}
总结
原型模式通过对象的复制机制,提供了一种高效创建相似对象的方式。浅克隆适用于简单对象,深克隆则适合复杂对象结构。
在 Java 中,借助 Cloneable 接口和 Clone()
方法,可以轻松实现原型模式。
参考文章: