说在前头:本人为大二在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,能力有限,文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正。若在阅读时有任何的问题,也可通过评论提出,本人将根据自身能力对问题进行一定的解答。
前言
原型模式是一种对象创建型模式,用原型模式可以用原型实例指定创建对象的种类,它允许通过一个原型对象创建多个同类型的其他对象,而无需知道该对象的创建细节,在Java中可以直接使用Object提供的clone()方法来实现对象的克隆(浅克隆),或使用序列化的方式完成对象的克隆(深克隆)。
浅克隆
浅克隆主要用于对象的复制,要实现浅克隆的类需要具备以下两个条件:
-
实现Cloneable接口。在java语言有一个Cloneable接口,它的作用只有一个,就是在运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法。在java虚拟机中,只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出CloneNotSupportedException异常。
-
重写Object类中的clone方法。Java中,所有类的父类都是Object类,Object类中有一个clone方法,作用是返回对象的一个拷贝,但是其作用域protected类型的,一般的类无法调用,因此,Prototype类需要将clone方法的作用域修改为public类型。
下面是浅克隆具体的代码实现:
package com.bosen.prototype;
/**
* <p>浅克隆</p>
* @author Bosen 2021/5/25 2:03
*/
public class ShallowPrototype implements Cloneable {
public String param = new String("测试参数");
/*
* 重写clone方法
*/
@Override
public ShallowPrototype clone() {
ShallowPrototype prototype = null;
try {
prototype = (ShallowPrototype) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return prototype;
}
}
测试类:
package com.bosen.prototype;
import java.io.IOException;
/**
* <p>测试类</p>
* @author Bosen 2021/5/25 2:14
*/
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ShallowPrototype prototype = new ShallowPrototype();
ShallowPrototype clone = prototype.clone();
System.out.println(clone.param == prototype.param);
}
}
运行测试类,输出信息如下:
可以得知,原型类与克隆类两者对应的成员变量的内存地址是一样的,也就是说浅克隆时,并未对原型类中的成员变量进行克隆,具体原因是因为原型模式使用浅克隆时,只复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量并不会去复制;如果要达到引用对象的克隆我们又该如何去实现呢?我们接下来看看深克隆!
深克隆
深克隆与浅克隆的区别:浅克隆是继承Cloneable接口后重写clone方法完成的克隆,而深克隆需要继承序列化接口Serializable,使类可以序列化,然后将类写入流中再从流中取出完成克隆。
深克隆具体代码:
package com.bosen.prototype;
import java.io.*;
/**
* <p>深克隆</p>
* @author Bosen 2021/5/25 2:18
*/
public class DeepPrototype implements Serializable {
public String param = new String("测试参数");
public Object deepClone() throws IOException, ClassNotFoundException {
// 将对象写入流中
ByteArrayOutputStream bao = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bao);
oos.writeObject(this);
// 将对象从流中取出
ByteArrayInputStream bai = new ByteArrayInputStream(bao.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bai);
return ois.readObject();
}
}
测试类:
package com.bosen.prototype;
import java.io.IOException;
/**
* <p>测试类</p>
* @author Bosen 2021/5/25 2:14
*/
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
DeepPrototype prototype = new DeepPrototype();
DeepPrototype clone = (DeepPrototype) prototype.deepClone();
System.out.println(clone.param == prototype.param);
}
}
启动测试类,输出信息如下:
可以看到,此时原型类的成员变量与克隆类的成员变量内存地址不一致了,也就是说他们的这个成员变量不属于同一个对象,成员变量已经完成了克隆。
总结
原型模式的作用:简化了创建对象的过程,通过一个已有的实例进行复制提高了创建实例的效率,具有较好的可扩展性。
浅克隆和深克隆的区别:使用浅克隆时,当原型对象被复制时,只复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量并没有复制;而使用深克隆时,除了对象本身被复制外,对象所包含的所有成员变量也将被复制。
原型模式的使用场景:适合于当一个类初始化需要消耗很多资源时,有很多相似对象时,可以设计一个原型,通过对成员变量的些微修改来实现;需要时可以用深克隆的方式保存对象的状态,比如实现撤销操作等。
👇扫描二维码关注