软件设计模式之原型模型(ProtoType Model)以及深复制和浅复制
欢迎各位大哥大姐访问个人博客码农峰酱
一、应用场景
- 对同一个对象或者类似对象需要多次进行实例化时;
- 对于实例化不方便而复制比较方便时。
二、原型模型定义
用一个已经创建的实例作为原型,通过复制该原型来创建一个和原型相同或者相似的新对象。在这里,原型对象指定了要创建的对象的种类,用这种方法创建对象非常有效,根本不需要知道创建对象的具体的细节。
三、原型模式中几个重要的角色:
(1)抽象原型类:规定了原型对象必须实现的接口;
(2)具体原型类:实现了抽象原型类的的clone()方法,是可以被复制的;
(3)访问类:使用具体类中的clone()方法来复制对象。
四、原型模式类图:
五、应用举例
应聘者对于不同的公司写不同的简历,但个人信息都相同,因此只需修改除个人信息之外的信息
常规做法是写一个简历类,根据不同的公司实现不同的简历对象,而原型模型:使用clone()方法,克隆多个不同的实例对象。使用原型模型,避免手动创建对象,不需要执行构造方法,减少工作量,提高性能。
1、浅复制
public class Resume implements Cloneable{/*实现Cloneable接口*/
private String name;
private String sex;
private int age;
private String company;
private List<Experiment> experimentList;
public List<Experiment> getExperimentList() {
return experimentList;
}
public void addExperimentList(Experiment experiment) {
this.experimentList .add(experiment);
}
public Resume(String name, String sex, int age, String company,List<Experiment> experimentList) {
this.name = name;
this.sex = sex;
this.age = age;
this.company = company;
this.experimentList =experimentList;
}
public void setCompany(String company) {
this.company = company;
}
public void Information(){
System.out.println("个人信息:");
System.out.println("Name:"+this.name+" Age:"+this.age+" Sex:"+this.age);
System.out.println("目标公司:"+this.company);
System.out.println("工作经历:");
for (Experiment experiment:experimentList) {
System.out.println("company:" + experiment.getCompanyName()+
" time:"+experiment.getTime()+"sallary:"+experiment.getSallary());
}
}
/* *实现Cloneable接口的clone()方法 * 浅复制 * */
public Object clone() throws CloneNotSupportedException{
return (Resume)super.clone();//调用父类clone()方法
}
public static void main(String[] args) throws CloneNotSupportedException {
List<Experiment> experimentList = new ArrayList<Experiment>();
Experiment experiment1 = new Experiment("Tecent","2019.06-2022-7",20000);
experimentList.add(experiment1);
Resume resume = new Resume("yafeng","man",23,"HuaWei",experimentList);
resume.Information();
Resume resume1 = (Resume)resume.clone();
resume1.setCompany("Alibaba");
resume1.Information();
}
}
上述代码的意思是当你第一次投递简历时你写了一份简历,所***司为华为;第二次再投阿里巴巴时,仅需修改目标公司的名称,其个人信息不变,这样做的好处就是省时省力,高效快捷。上述代码输出的结果如下:
个人信息:
Name:yafeng Age:23 Sex:23
目标公司:HuaWei
工作经历:
company:Tecnet time:2019.06-2022-7sallary:20000.0
个人信息:
Name:yafeng Age:23 Sex:23
目标公司:Alibaba
工作经历:
company:HuaWei time:2019.06-2022-7sallary:20000.0
那么到底什么是浅复制呢?在上述代码的基础上再添加如下代码,即向resume对象的experimentList属性中再添加一个数据,代码如下:
System.out.println("=======================================举例说明浅复制=====================================");
Experiment experiment2 = new Experiment("Baidu","2022.08-2025-7",30000);
resume.addExperimentList(experiment2);
System.out.println(resume == resume1);
System.out.println(resume.getExperimentList() == resume1.getExperimentList());
输出结果如下:
=======================================举例说明浅复制=====================================
个人信息:
Name:yafeng Age:23 Sex:23
目标公司:Alibaba
工作经历:
company:Tecent time:2019.06-2022-7sallary:20000.0
company:Baidu time:2022.08-2025-7sallary:30000.0
false
true
resume == resume1为false,即resume 和resume1两个不同的对象,而resume.getExperimentList() == resume1.getExperimentList()为true说明在对象复制时仅仅复制了该对象属性的引用,而从上述输出中也可以看出,在给resume对象的experimentList属性添加一个数据时,resume1的experimentList属性也发生了变化,这就是浅复制。
浅复制总结成一句话就是:通过clone方法复制时,对象的属性通过复制引用的方式来完成对象复制的一种复制方式。
2、深复制(通过对象流实现)
将述代码中Resume和Experience两个类实现的接口换为Serializable,除测试代码其他的代码均不变,测试代码如下:
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
Resume resume=new Resume("yafeng","男",21);
WorkExperimence workExperimence1= new WorkExperimence("Tencent","2015.07-2019.06",20000);
resume.getWorkExperimenceList().add(workExperimence1);
//将对象转换为字节写入流中
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oops = new ObjectOutputStream(baos);
oops.writeObject(resume);
//从流中读出
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
Resume resume1 = (Resume) ois.readObject();
System.out.println("============================举例说明深复制=======================================");
System.out.println(resume == resume1);
System.out.println(resume.getWorkExperimenceList() == resume1.getWorkExperimenceList());
}
输出结果:
=========================举例说明深复制==================================
false
false
上述结果说明,深复制当中,复制后的对象和原对象是两个完全不同的对象,没有任何关联,只是它们的属性值都是相同的,后续对任何一个的修改或其他操作都不会对另外一个有影响!本文是通过对象流的读写来完成深复制的。