目录
定义
类图
角色
优缺点
优点
缺点
应用场景
案例展示
浅克隆
深克隆
定义
原型模式旨在创建重复的对象,同时确保良好的性能表现。它通过复制现有对象(原型)来创建新对象,而非使用传统的构造函数创建方式。这种设计模式属于创建型模式,为对象创建提供了一条便捷、高效的途径。其核心在于,通过复制原型对象的属性和状态,极大地减少了新对象创建过程中的资源消耗和时间成本。
类图
角色
-
原型(Prototype):声明一个克隆自身的接口,这是所有支持克隆操作的类的通用接口。它为具体原型类定义了克隆方法的规范,使得具体原型类只需实现该接口,就能实现对象的克隆。
-
具体原型(Concrete Prototype):实现原型接口,定义克隆方法。在克隆方法中,具体原型类会创建一个与自身属性和状态相同的新对象,并返回该对象。
优缺点
优点
-
性能优势:Java 自带的原型模式基于内存二进制流的复制,相比直接使用new关键字创建对象,能显著提升性能。在创建复杂对象时,new操作需要经历类的加载、初始化等一系列过程,而原型模式通过复制内存中的对象,避免了这些繁琐的步骤,大幅缩短了对象创建的时间。
-
状态保存与恢复:借助深克隆,原型模式可以完整地保存对象的状态。这一特性在实现撤销操作或恢复对象历史状态时极为有用。通过克隆并保存对象的特定状态,程序能够在需要时轻松恢复到之前的状态,简化了状态管理的复杂度。
缺点
-
违背开闭原则:由于clone方法位于类的内部,对已有类进行改造以支持原型模式时,需要修改类的代码。这与开闭原则相悖,可能导致代码的可维护性降低,尤其是在大型项目中,牵一发而动全身,增加了系统的维护成本。
-
深克隆实现复杂:在实现深克隆时,需要编写复杂的代码。当对象之间存在多重嵌套引用时,为了确保所有层次的对象都能被正确克隆,每个层次的对象对应的类都必须支持深克隆,这无疑增加了实现的难度和复杂性。
应用场景
-
对象相似性高:当系统中需要创建多个相似对象,仅个别属性不同时,原型模式是理想的选择。以游戏开发为例,游戏中的角色通常具有相似的基本属性和行为,使用原型模式可以通过克隆一个基础角色,然后修改特定属性,快速创建多个不同的角色实例。
-
创建成本高昂:在创建对象成本较大的情况下,如初始化时间长、占用大量 CPU 资源或网络资源,原型模式可以优化资源使用。比如,创建一个需要从数据库加载大量数据并进行复杂计算的对象,通过克隆已有的对象,可以避免重复的加载和计算过程,提高系统的响应速度。
-
数据准备繁琐:当创建对象需要繁琐的数据准备或特定的访问权限时,原型模式可以简化对象的创建过程,提高性能和安全性。例如,创建一个需要经过多层权限验证和复杂数据配置的对象,通过克隆已有的合法对象,可以减少不必要的验证和配置步骤。
-
大量对象需重新赋值:在系统中大量使用某类对象,且每个调用者都需要为其属性重新赋值的场景下,原型模式可以通过克隆对象,快速满足不同调用者的需求,减少重复创建对象的开销。
案例展示
浅克隆
-
浅克隆是使用默认的 clone()方法来实现
-
基本数据类型的成员变量,浅克隆会直接进行值传递(复制属性值给新对象)
-
引用数据类型的成员变量,浅克隆会进行引用传递(复制引用值(内存地址)给新对象)
-
在原先Sheep 类基础上实现 Cloneable 接口,重写 clone 方法。
public class Sheep implements Cloneable{
private String name;
private int age;
@Override
protected Object clone() {//克隆该实例,使用默认的clone方法来完成
Sheep sheep = null;
try {
sheep = (Sheep)super.clone();
} catch (Exception e) {
System.out.println(e.getMessage());
}
return sheep;
}
public Sheep(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
深克隆
-
方法1:
-
引用对象也实现 Cloneable 接口
-
对象调用引用对象的clone 方法
-
-
方法2:
-
实现序列化接口,不必实现Cloneable 接口了
-
public class Sheep implements Serializable { //实现序列化接口
private String name;
private int age;
public Cow friend;
public Sheep(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Object deepClone() { //深拷贝
//创建流对象
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
//序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this); //当前这个对象以对象流的方式输出
//反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
Sheep sheep = (Sheep) ois.readObject();
return sheep;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
//关闭流
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (Exception e2) {
System.out.println(e2.getMessage());
}
}
}
}