使用原型实例指定将要创建的对象类型,通过复制这个实例创建(新的对象)
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.io.*;
import java.util.Date;
/**
* @desc 需要多份简历投送到不同公司
*/
@Data
@Slf4j
public class Resume implements Cloneable, Serializable {
private String name;
private int age;
private Date resumeDate;
private JobExperience jobExperience;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class JobExperience implements Serializable {
private Integer salary;
private String duty;
}
public Resume() {
this.name = "xzz";
this.age = 15;
this.resumeDate = new Date();
this.jobExperience = new JobExperience(19900, "喝酒");
log.info("-----------resume构造方法-------------");
}
/**
* 浅clone 八大基本数据类型和String(默认浅克隆)
* 直接将原对象中的jobExperience的引用值拷贝给新对象的jobExperience字段
*
* @return
*/
public Resume shallowClone() {
try {
return (Resume) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
/**
* 深clone
* 根据原Resume对象中的jobExperience指向的对象创建一个新的相同的对象,
* 将这个新对象的引用赋给新拷贝的Resume对象的jobExperience字段
*/
public Resume 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);
Resume resume = (Resume) ois.readObject();
resume.setResumeDate(new Date());
resume.setJobExperience(new JobExperience(18000, "发呆"));
return resume;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
/**
* TODO 原型模式的要求是需要clone出来的对象是不同的实例
* 如果使用shallowClone()方法那么 (this.jobExperience==clone.jobExperience) is true
* 因为shallowClone()是浅拷贝,浅拷贝直接将原对象中的jobExperience的引用值拷贝给新对象的jobExperience字段(拷贝引用)
* 如果使用deepClone()方法那么 (this.jobExperience==clone.jobExperience) is false
* 因为deepClone()是深拷贝,深拷贝是先根据原对象Resume中的jobExperience的指向创建一个新的对象,然后赋值给新拷贝的Resume对象中的jobExperience
*/
public void resumeShallow() {
Resume clone = shallowClone();
log.info("resume 与 clone resume:{}为false则表示两个对象相互独立", (this == clone));
log.info("job time: this:{},clone:{}", this.resumeDate.getTime(), clone.getResumeDate().getTime());
// ==比较的就是两个对象的引用是否相同,引用相同那么就是同一个实例,则不满足原型模式的要求
log.info("jobExperience如果为true表示持有相同引用:{}", (this.jobExperience == clone.jobExperience));
log.info("基本类型int深浅拷贝:{}", this.getAge() == clone.getAge());
log.info("String类型深浅拷贝:{}", this.getName() == clone.getName());
log.info("resume:{} \r\n clone resume:{}", this.toString(), clone.toString());
}
public void resumeDeep() {
Resume clone = deepClone();
log.info("resume 与 clone resume为false则表示两个对象相互独立:{}", (this == clone));
log.info("job time: this:{},clone:{}", this.resumeDate.getTime(), clone.getResumeDate().getTime());
log.info("jobExperience如果为true表示持有相同引用:{}", (this.jobExperience == clone.jobExperience));
log.info("基本类型int深浅拷贝:{}", this.getAge() == clone.getAge());
log.info("String类型深浅拷贝:{}", this.getName() == clone.getName());
log.info("resume:{} \r\n clone resume:{}", this.toString(), clone.toString());
}
@Override
public String toString() {
return "Resume{" +
"name='" + name + '\'' +
", age=" + age +
", resumeDate=" + resumeDate +
", jobExperience=" + jobExperience +
'}';
}
}
public class ResumeTest {
public static void main(String[] args) {
Resume resume = new Resume();
resume.resumes();
}
}
clone是字节码复制(所以性能比较好)
注意事项:
1.不需要调用对象的构造方法
2.原型模式与单例模式有冲突,
3.浅拷贝并不适合与原型模式中使用,更多情况下我们需要一个不会影响原始对象的一个新对象,也就需要使用深拷贝,
总结
原型模式的本质就是clone,可以解决构建复杂对象的资源消耗问题,可以返回一个对象的拷贝,从而保护原对象(多用于只读)
clone参考链接:https://blog.csdn.net/zhangjg_blog/article/details/18369201/
网友评论