原型模式:通过复制已有对象(原型)来创建新对象,而不是 new 新建对象,适合对象创建成本高的场景。 Java 两种实现方式:
实现
Cloneable接口,重写clone()(浅拷贝)序列化实现深拷贝
1、浅拷贝示例(Cloneable)
原型对象
// 实现Cloneable标记接口
class Sheep implements Cloneable {
private String name;
private int age;
// 引用类型成员,浅拷贝会共用同一个对象
private Friend friend;
public Sheep(String name, int age, Friend friend) {
this.name = name;
this.age = age;
this.friend = friend;
}
// 重写clone,浅拷贝
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
// getter setter toString
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public Friend getFriend() { return friend; }
public void setFriend(Friend friend) { this.friend = friend; }
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
", friend=" + friend +
'}';
}
}
// 引用类
class Friend {
private String nickName;
public Friend(String nickName) {
this.nickName = nickName;
}
public String getNickName() { return nickName; }
public void setNickName(String nickName) { this.nickName = nickName; }
@Override
public String toString() {
return "Friend{" + "nickName='" + nickName + '\'' + '}';
}
}
客户端测试
public class PrototypeDemo {
public static void main(String[] args) throws CloneNotSupportedException {
// 原始原型对象
Friend friend = new Friend("小黑");
Sheep original = new Sheep("多利", 2, friend);
// 使用原型克隆对象
Sheep cloneSheep = (Sheep) original.clone();
System.out.println("原对象:" + original);
System.out.println("克隆对象:" + cloneSheep);
System.out.println("====================");
System.out.println("对象地址是否相同:" + (original == cloneSheep));
// 浅拷贝:引用类型还是同一个对象
System.out.println("friend引用是否同一对象:" + (original.getFriend() == cloneSheep.getFriend()));
// 修改克隆对象里的引用属性,原对象也会被影响【浅拷贝坑点】
cloneSheep.getFriend().setNickName("小白");
System.out.println("\n修改克隆对象的引用属性后");
System.out.println("原对象:" + original);
System.out.println("克隆对象:" + cloneSheep);
}
}
浅拷贝效果:基本数据类型复制值;引用类型只复制引用地址,新旧对象指向同一个子对象。
2、深拷贝实现(两种方式)
方式 1:clone 手动递归拷贝引用对象
class SheepDeep implements Cloneable {
private String name;
private int age;
private Friend friend;
public SheepDeep(String name, int age, Friend friend) {
this.name = name;
this.age = age;
this.friend = friend;
}
@Override
protected Object clone() throws CloneNotSupportedException {
// 先拷贝基础属性
SheepDeep sheep = (SheepDeep) super.clone();
// 手动克隆引用对象,新建Friend
sheep.friend = new Friend(this.friend.getNickName());
return sheep;
}
// getter setter toString
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public Friend getFriend() { return friend; }
public void setFriend(Friend friend) { this.friend = friend; }
@Override
public String toString() {
return "SheepDeep{" +
"name='" + name + '\'' +
", age=" + age +
", friend=" + friend +
'}';
}
}
方式 2:序列化实现通用深拷贝(推荐,多层对象不用手动写 clone)
所有参与对象实现
Serializable
import java.io.*;
/**
* 序列化工具实现深拷贝
*/
public class DeepCloneUtil {
@SuppressWarnings("unchecked")
public static <T extends Serializable> T deepClone(T obj) {
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
// 序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
// 反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
return (T) ois.readObject();
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
try {
if(oos != null) oos.close();
if(bos != null) bos.close();
if(ois != null) ois.close();
if(bis != null) bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
实体类增加序列化标记:
import java.io.Serializable;
class Friend implements Serializable {
// ...原有代码
}
class Sheep implements Serializable {
// ...原有代码
}
调用:
Sheep clone = DeepCloneUtil.deepClone(original);
3、原型模式 UML 角色说明
Prototype(原型抽象):声明克隆自身的接口(
Cloneable)ConcretePrototype(具体原型):实现克隆方法(Sheep)
Client(客户端):拿到原型对象,调用 clone 复制出新对象
4、适用场景
对象创建成本很高(大量 IO、数据库查询),复制比 new 性能更好
需要大量相似对象,仅少量属性不同
保护原有对象,不希望直接修改原型实例
5、注意点
Cloneable只是标记接口,没有任何方法,不重写 clone 会抛异常Object.clone()默认是浅拷贝,包含引用类型要做深拷贝序列化深拷贝性能略差,但支持任意层级对象;手动 clone 性能好,嵌套对象多时代码繁琐