文章目录
原型设计模式
一、举个小栗子
举个栗子:
现在有一个对象,如果我们需要对创建多个与该对象属性一致的对象
,不能是使用 =
直接进行赋值的。
在创建新的对象的时候,总是要重新获取原始对象的属性,设置到新建的对象中
,在创建的对象比较复杂的情况下,效率是比较低
。
例如:
public class Example{
public static void main(String[] args){
User originUser = new User(1,"kuyin");
// 下面是对象复制功能,
User copyUser = new User();
copyUser.setId(originUser.getId());
copyUser.setName(originUser.getName());
}
}
class User{
private int id;
private String name;
public User (){}
public User(int id, String name){
this.id = id ;
this.name =name;
}
// 省略setter 和 getter 方法
}
从上面的栗子中,可以看到通过getXxx()
获取到原有的值,然后使用setXxx()
设置到新建的对象,一旦创建多个对象的时候,这是一个重复且无聊
的动作。
所以就会会进行优化改进,这个时候就是原型设计模式出场的时候了。
二、原型模式的相关概念
1、原型模式(Prototype)
- 用原型时指定创建对象的种类,
并通过拷贝这些原型,创建新的对象。
- 是一种
创建型的设计模式
,允许对象在创建一个可定制的对象,无需知道如何创建的细节。
2、实现思路一:利用Object的clone()方法(浅拷贝的方式)
利用java.lang.Object
方法里就提供了克隆方法clone()
,但是在使用clone()
方法进行复制还是有下面的限制的:
- 要实现克隆,必须实现
java.lang.Cloneable接口
,否则在运行时调用clone()
方法,会抛出CloneNotSupportedException
异常。 - 返回的是
Object
类型的对象,所以使用时可能需要强制类型转换。 - .该方法是
protected
的,如果想让外部对象使用它,必须在子类重写该方法,设定其访问范围是public的,参见PackageInfo的clone()
方法。 Object类
的clone()
方法的复制是采用逐字节的方式从内存复制数据
,复制了属性的引用
,而属性所指向的对象本身没有被复制
,因此所复制的引用指向了相同的对象
。由此可见,用这种方式复制对象是浅拷贝
,不是深拷贝。
关于浅拷贝和深拷贝相关知识的可以查看该文章:
Java基础:浅复制、深复制、克隆接口Clone以及clone()方法
原型模式对于复杂的对象,往往需要进行深拷贝的。
3、深拷贝的实现方式两种实现方式
1、重写clone()
方法来实现深拷贝。
- 这种方式在Java基础:浅复制、深复制、克隆接口Clone以及clone()方法 这篇文章中已经讲的比较清楚了,这里就不进行过多说明,主要还是第二种方式。
2、通过对象序列化和反序列化
来实现深拷贝(推荐
)
三、通过对象序列化和反序列化来实现深拷贝(推荐)
1、一言不合就是上代码
package design.model.prototype;
import java.io.*;
public class DeepConyBean implements Serializable {
private Integer id;
private OtherBean other;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public OtherBean getOther() {
return other;
}
public void setOther(OtherBean other) {
this.other = other;
}
@Override
public String toString() {
return "DeepConyBean{" +
"id=" + id +
", other=" + other +
'}';
}
public DeepConyBean deepCony(){
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos= new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
DeepConyBean copyBean = (DeepConyBean)ois.readObject();
return copyBean;
}catch (IOException exception){
exception.printStackTrace();
}catch ( ClassNotFoundException exception){
exception.printStackTrace();
}
return null;
}
}
class OtherBean implements Serializable{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "OtherBean{" +
"name='" + name + '\'' +
'}';
}
}
2、行不行,试试就只知道
测试代码
package design.model.prototype;
public class DeepCopyTest{
public static void main(String[] args) {
// 创建原型
DeepConyBean origin = new DeepConyBean();
origin.setId(1);
OtherBean otherBean = new OtherBean();
otherBean.setName("origin");
origin.setOther(otherBean);
// 执行深度复制
DeepConyBean copy = origin.deepCony();
System.out.println("---------通过==判断引用地址是否相同---------");
System.out.println("origin == copy?" +(origin == copy));
System.out.println("origin.other == copy.other?" +(origin.getOther() == copy.getOther()));
System.out.println("---------查看数据---------");
System.out.println("origin:"+origin);
System.out.println("copy:"+copy);
// 修改copy
copy.setId(2);
copy.getOther().setName("copy");
System.out.println("---------修改后---------");
System.out.println("origin:"+origin);
System.out.println("copy:"+copy);
}
}
3、深度拷贝的结果
执行结果及分析:
- 对象引用的地址不想同,成员变量指向的地址也不想同。
- 对复制后的
copy
对象进行修改,不会影响origin
对象的值。