原型模式小结
Posted chen-ying
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原型模式小结相关的知识,希望对你有一定的参考价值。
一、原型模式
原型模式就是从一个对象再创建另一个可定制的对象,而且不需要知道任何创建的细节。
二、基本的原型模式
这里模拟简历的创建与复制来说明原型模式的应用。
class Resume implements Cloneable private String name; private String sex; private String age; private String timeArea; private String company; public Resume(String name) this.name=name; //设置个人信息 public void setPersonalInfo(String sex,String age) this.sex=sex; this.age=age; //设置工作经历 public void setWorkExperience(String timeArea,String company) this.timeArea=timeArea; this.company=company; //打印 public void display() System.out.println("name sex age:"+name+" "+sex+" "+age); System.out.println("work experience"+timeArea+" "+company); @Override protected Object clone() throws CloneNotSupportedException return super.clone(); public class PrototypePattern public static void main(String[] args) throws CloneNotSupportedException Resume a = new Resume("a的简历"); a.setPersonalInfo("male", "18"); a.setWorkExperience("2017", "companya"); Resume b=(Resume) a.clone(); b.setWorkExperience("2016","companyb"); Resume c=(Resume) a.clone(); c.setWorkExperience("2019","companyc"); a.display(); b.display(); c.display();
输出结果:
三、原型模式中的浅复制与深复制
上面的Resume类通过实现Cloneable接口才能使用clone方法,进行对象的克隆。
Java中对象的创建通常是通过new来实现的,通过从堆中申请一块与需要的对象类型对应的内存空间的大小,在调用构造方法返回对象给引用,
假如需要创建一批属性值都相同的对象,或许可以通过new一批对象来实现,但是这样的话,效率未免太低,并不划算。
那么如果是这样呢?
class PersonTest public class Test public static void main(String[] args) PersonTest personTest=new PersonTest(); PersonTest personTest1=personTest; System.out.println(personTest); System.out.println(personTest1);
输出结果:
可见personTest和personTest1的地址是一样的,说明他们两个其实是指向同一个对象的引用,在这个过程中并没有进行对象的复制。
那如果是进行一次克隆呢?像这样:
class Person implements Cloneable int id; String name; Education education; public Person(int id, String name,Education education) this.id = id; this.name = name; this.education=education; public int getId() return id; public void setId(int id) this.id = id; public String getName() return name; public void setName(String name) this.name = name; public Education getEducation() return education; public void setEducation(Education education) this.education = education; @Override protected Object clone() throws CloneNotSupportedException return super.clone(); class Education String theUniversity; String degree; public Education(String theUniversity, String degree) this.theUniversity = theUniversity; this.degree = degree; public String getTheUniversity() return theUniversity; public void setTheUniversity(String theUniversity) this.theUniversity = theUniversity; public String getDegree() return degree; public void setDegree(String degree) this.degree = degree; public class ObjectClone public static void main(String[] args) throws CloneNotSupportedException Education educationA=new Education("清华大学","学士"); Person personA=new Person(1,"小明",educationA); Person personB=(Person) personA.clone(); System.out.println(personA==personB); System.out.println(personA.id==personB.id); System.out.println(personA.name==personB.name); System.out.println(personA.education==personB.education); System.out.println(); System.out.println(personA); System.out.println(personB); System.out.println(personA.id); System.out.println(personB.id); System.out.println(personA.name); System.out.println(personB.name); System.out.println(personA.education); System.out.println(personB.education);
输出结果:
可见克隆以后进行了对象的复制,personA与personB的地址是不同的,复制以后两个对象的id值与name,education都相同,比较结果都为true,乍看上去这好像是预期中的现象。
但是,
name作为String对象,在进行“==”的比较时比较的是对象是否相同,可见这次复制过程中,name的值并没有复制,
Education的值是一个对象,education的地址也相同,
所以这次对象复制后的情况,为什么跟上面的例子只传引用没有什么区别啊?
克隆的过程中有几个问题需要进行思考,
id作为int型数据,int是基本数据类型,复制的过程当中是逐位复制的,
但是对于String类型与其他引用类型,这里都只是将原对象的引用值拷贝给了新对象的相应字段。
这种就是浅复制,clone()方法进行的就是浅拷贝,这是需要注意的问题。
那么如果需要进行深拷贝,则需要将clone()方法进行覆盖,并且在clone()方法内把原对象引用的其他对象也拷贝一份。
那么被引用的对象也需要实现Cloneable接口,并且实现clone()方法。
class Person implements Cloneable int id; String name; Education education; public Person(int id, String name,Education education) this.id = id; this.name = name; this.education=education; @Override protected Object clone() throws CloneNotSupportedException Person person=(Person) super.clone(); person.education=(Education) education.clone(); return person; class Education implements Cloneable String theUniversity; String degree; public Education(String theUniversity, String degree) this.theUniversity = theUniversity; this.degree = degree; @Override protected Object clone() throws CloneNotSupportedException return super.clone(); public class ObjectClone public static void main(String[] args) throws CloneNotSupportedException Education educationA=new Education("清华大学","学士"); System.out.println(educationA); Person personA=new Person(1,"小明",educationA); Person personB=(Person) personA.clone(); System.out.println(personA==personB); System.out.println(personA.id==personB.id); System.out.println(personA.name==personB.name); System.out.println(personA.education==personB.education); System.out.println(); System.out.println(personA); System.out.println(personB); System.out.println(personA.id); System.out.println(personB.id); System.out.println(personA.name); System.out.println(personB.name); System.out.println(personA.education); System.out.println(personB.education);
输出结果如下:
代码跟上方相比,有一点点改动,但是根据输出结果来看,这次原对象中的某些字段的所引用的对象也进行了拷贝了。
四、关于clone的总结
由此可见clone()只是浅拷贝,也就是说除非基本类型外,引用类型只是拷贝引用,不会复制对象。
如果需要进行深拷贝,则需要使原对象所引用的对象类型也要继承Cloneable接口,并且实现clone()方法,同时要注意对象与对象之间存在的嵌套问题,避免拷贝后的两个对象仍然因为引用的某个对象存在关系。
五、关于Cloneable接口
上面提到了Cloneable接口,再对这个东西多了解一点,下面这个就是Cloneable接口,可见当中没有任何方法和属性。
Cloneable接口与Serializable接口一样,都是标记型的接口,
实现 Cloneable来表示该对象能被克隆,能使用Object.clone()方法。如果没有实现 Cloneable的类对象调用clone()就会抛出CloneNotSupportedException。
如果将上面最后一个实例代码中Education类实现的Cloneable接口去除,那么程序运行时会出现异常,
这里想思考的是标记型接口是如何起作用的呢?
标记接口是没有任何方法和属性的接口,仅仅表明实现它的类是属于一个特定的类型,我们知道实现一个接口的类是可以来代表这个接口类型的。
通常创建标记接口的目的就是主要是:
建立一个公共的父接口,之后可以通过多态对其进行扩展,但是Java虚拟机却可以根据这个接口的类型选择相应的事件处理方案,也就是对实现这个标记接口的对象进行这个处理方案。
关于标记接口的作用描述还是不够清晰,待之后学习的再深入一点再继续探究吧。
以上是关于原型模式小结的主要内容,如果未能解决你的问题,请参考以下文章