原型(Prototype)模式
原型(Prototype)模式
模式定义:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。
-
1:Cloneable接口/Object#clone方法
-
2:浅拷贝/深拷贝
-
2.1:浅拷贝(Shallow Copy):①对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,不会影响另一个对象拷贝得到的数据。②对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。
-
2.2:深拷贝:首先介绍对象图的概念。设想一下,一个类有一个对象,其成员变量中又有一个对象,该对象指向另一个对象,另一个对象又指向另一个对象,直到一个确定的实例。这就形成了对象图。那么,对于深拷贝来说,不仅要复制对象的所有基本数据类型的成员变量值,还要为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象图进行拷贝!
简单地说,深拷贝对引用数据类型的成员变量的对象图中所有的对象都开辟了内存空间;而浅拷贝只是传递地址指向,新的对象并没有对引用数据类型创建内存空间。
-
3:序列化机制实现深拷贝
package Prototype;
public class PrototypeTest {
public static void main(String[] args) throws CloneNotSupportedException {
BaseInfo baseInfo = new BaseInfo("xxx");
Product product = new Product("part1", "part2", "part3",baseInfo);
Object clone = product.clone();
System.out.println("original:"+product); //original:1735600054 ] Product{part1='part1', part2='part2', part3='part3', baseInfo=21685669 ] BaseInfo{companyName='xxx'}}
System.out.println("clone: "+clone); //clone: 2133927002 ] Product{part1='part1', part2='part2', part3='part3', baseInfo=21685669 ] BaseInfo{companyName='xxx'}}
product.getBaseInfo().setCompanyName("yyy");
System.out.println("original:"+product);//original:1735600054 ] Product{part1='part1', part2='part2', part3='part3', baseInfo=21685669 ] BaseInfo{companyName='yyy'}}
System.out.println("clone: "+clone);//clone: 2133927002 ] Product{part1='part1', part2='part2', part3='part3', baseInfo=21685669 ] BaseInfo{companyName='yyy'}}
//改变原始的公司名字,会导致之前克隆的也改变,hashcode值是一样的
//深拷贝 test结果修改完代码自己测试即可,检查结果
}
}
//实现Cloneable
class BaseInfo implements Cloneable{
private String companyName;
public BaseInfo(String companyName) {
this.companyName = companyName;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
@Override
public int hashCode() {
return super.hashCode();
}
@Override
public String toString() {
return super.hashCode()+" ] BaseInfo{" +
"companyName='" + companyName + '\'' +
'}';
}
@Override
protected BaseInfo clone() throws CloneNotSupportedException {
return ( (BaseInfo) super.clone());
}
}
//1克隆机制,实现Cloneable
class Product implements Cloneable{
private String part1;
private String part2;
private String part3;
private BaseInfo baseInfo;
public Product() {
}
public Product(String part1, String part2, String part3,BaseInfo baseInfo) {
this.part1 = part1;
this.part2 = part2;
this.part3 = part3;
this.baseInfo=baseInfo;
}
public String getPart1() {
return part1;
}
public BaseInfo getBaseInfo() {
return baseInfo;
}
public void setBaseInfo(BaseInfo baseInfo) {
this.baseInfo = baseInfo;
}
public void setPart1(String part1) {
this.part1 = part1;
}
public String getPart2() {
return part2;
}
public void setPart2(String part2) {
this.part2 = part2;
}
public String getPart3() {
return part3;
}
public void setPart3(String part3) {
this.part3 = part3;
}
/**
* 实现此接口的类应该使用公共方法重写Object的clone()方法,Object的clone()方法是一个受保护的方法
* 直接在里面强制装换位Product
* @return
* @throws CloneNotSupportedException
*/
//浅拷贝:
// @Override
// protected Product clone() throws CloneNotSupportedException {
// return ((Product) super.clone());
// }
/**
*深拷贝
*/
@Override
protected Product clone() throws CloneNotSupportedException {
Product clone = (Product) super.clone();
BaseInfo clone1 = this.baseInfo.clone();
clone.setBaseInfo(clone1);
return clone;
}
@Override
public String toString() {
return super.hashCode()+ " ] Product{" +
"part1='" + part1 + '\'' +
", part2='" + part2 + '\'' +
", part3='" + part3 + '\'' +
", baseInfo=" + baseInfo +
'}';
}
@Override
public int hashCode() {
return super.hashCode();
}
}
应用场景:当代码不依赖于需要复制的对象的具体类时,使用Prototype 模式。
优点:
- 1:可以不耦合具体类的情况下克隆
- 2:避免重复的初始化代码
- 3:更方便的构建复杂对象