原型模式
设计模式
原型模式
定义:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的对象。
特点:
1、简化对象创建的流程,同时也可以提高效率
2、如果原始对象发生变化,其克隆对象也会发生相应变化,无需修改代码
劣势:
1、每个对象都需要配备一个克隆方法,违反OCP(开闭)原则
原型模式的拷贝分为浅拷贝与深拷贝
浅拷贝
对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递
对于数据类型是引用数据类型的成员变量,那么浅拷贝会进行引用传递
以打印简历为例:
package com.prototype;
public class Resume implements Cloneable{
private String name;
private boolean sex;
private String salary;
private Witness witness;//见证人
/*
简历类
浅拷贝:
1. 实现Cloneable接口
2. 重写clone()方法
*/
//略写有参无参构造方法,set、get方法
//重写clone方法
protected Object clone() throws CloneNotSupportedException {
System.out.println("复制简历成功!!");
Resume clone = (Resume) super.clone();
return clone;
}
@Override
public String toString() {
return "Resume [name=" + name + ", sex=" + sex + ", salary=" + salary
+ "]";
}
}
package com.prototype;
//客户端
public class Client {
public static void main(String[] args) {
Resume resume = new Resume("jack", true, "面试");
resume.setWitness(new Witness("mary", "经理"));
//打印2份简历
for (int i = 0; i < 2; i++) {
try {
Resume clone = (Resume) resume.clone();
System.out.println("打印简历:"+clone);
System.out.println("resume的哈希值"+clone.hashCode());
System.out.println("witness的哈希值"+clone.getWitness().hashCode());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
}
package com.prototype;
//见证人 类
public class Witness{
private String name;//姓名
private String job;//职位
//略写有参无参构造方法,set、get方法
@Override
public String toString() {
return "Witness [name=" + name + ", job=" + job + "]";
}
}
显示:
复制简历成功!!
打印简历:Resume [name=jack, sex=true, salary=面试, witness=Witness [name=mary, job=经理]]
resume的哈希值1167165921
witness的哈希值1442002549
复制简历成功!!
打印简历:Resume [name=jack, sex=true, salary=面试, witness=Witness [name=mary, job=经理]]
resume的哈希值1383884648
witness的哈希值1442002549
结果:resume克隆对象的内容一样,但不是同一个对象,其中属性witness进行的是引用传递
深拷贝:
实现方式1:重写clone()方法(不推荐)
缺点:虽然层次调用clone方法可以实现深拷贝,但是显然代码量实在太大。特别对于属性数量比较多、层次比较深的类而言,每个类都要重写clone方法太过繁琐。
也是以打印简历为例:
package com.prototype;
public class Resume2 implements Cloneable{
//简历2.0版本
private String name;
private int age;
private String salary;
private Witness witness;
//略写有参无参构造方法,set、get方法
@Override
protected Object clone() throws CloneNotSupportedException {
/*
* 完成深拷贝
* 实现方式1:重写clone()方法
* */
//第一步:完成对基本数据类型或String类型的拷贝
Resume2 resume2 = (Resume2)super.clone();
//第二步:对引用类型进行处理(引用类型也要实现Cloneable接口,重写clone方法)
resume2.witness = (Witness) witness.clone();
return resume2;
}
}
package com.prototype;
//见证人 类
public class Witness implements Cloneable{
private String name;
private String job;
//略写有参无参构造方法,set、get方法 ,toString方法
@Override
protected Object clone() throws CloneNotSupportedException {
return (Witness)super.clone();
}
@Override
public String toString() {
return "Witness [name=" + name + ", job=" + job + "]";
}
}
package com.prototype;
public class Client2 {
public static void main(String[] args) {
Resume2 resume2 = new Resume2("jack", 20, "面议");
resume2.setWitness(new Witness("mary", "经理"));
for (int i = 0; i < 2; i++) {
try {
Resume2 clone1 = (Resume2) resume2.clone();
System.out.println("打印简历:"+clone1);
System.out.println("clone1的哈希值:"+clone1.hashCode());
System.out.println("witness的哈希值:"+clone1.getWitness().hashCode());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
}
显示:
打印简历:Resume2 [name=jack, age=20, salary=面议, witness=Witness [name=mary, job=经理]]
clone1的哈希值:1167165921
witness的哈希值:1442002549
打印简历:Resume2 [name=jack, age=20, salary=面议, witness=Witness [name=mary, job=经理]]
clone1的哈希值:1383884648
实现方式2:通过对象序列化(推荐)
特点:一步到位不管类的结构和如何复杂,整体处理
注意:如果某个属性被transient修饰,那么该属性就无法被拷贝了
步骤:1.要进行拷贝的类要实现Serializable接口 2.进行序列化与反序列化
package com.prototype;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Resume3 implements Serializable{
//简历 3.0版本
private String name;
private int age;
private String salary;
private Witness witness;//Witness类也要实现Serializable接口
//set get方法,有参无参构造函数略写
//对象序列化与反序列化
public Resume3 deepClone(){
ByteArrayOutputStream bos = null;
ByteArrayInputStream bis = null;
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
Resume3 resume3 = null;
try {
//对象序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
resume3 = ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
try {
//关闭流
bos.close();
oos.close();
bis.close();
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return resume3;
}
@Override
public String toString() {
return "Resume3 [name=" + name + ", age=" + age + ", salary=" + salary
+ ", witness=" + witness + "]";
}
}
package com.prototype;
import java.io.Serializable;
public class Witness implements Serializable{
private String name;
private String job;
//略写set get toString方法
}
package com.prototype;
//客户端
public class Client3 {
public static void main(String[] args) {
Resume3 resume3 = new Resume3("jack", 20, "面议");
resume3.setWitness(new Witness("mary", "经理"));
Resume3 d1 = resume3.deepClone();
Resume3 d2 = resume3.deepClone();
System.out.println(d1);
System.out.println(d2);
System.out.println(d1.hashCode()+" "+d2.hashCode());
System.out.println(d1.getWitness().hashCode()+" "+d2.getWitness().hashCode());
}
}
显示:
Resume3 [name=jack, age=20, salary=面议, witness=Witness [name=mary, job=经理]]
Resume3 [name=jack, age=20, salary=面议, witness=Witness [name=mary, job=经理]]
1932154105 1613816448
694579926 83711190