介绍:
是一个创建型的模式。原型表明该模式应该有一个样板实例,用户从这个样板对象中复制一个内部属性一致的对象,即为:克隆。原型可定制,该模式多用于创建复杂的或者构建耗时的实例,这种情况下,复制一个已经存在的实例可使程序运行的更高效。
定义:
用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
使用场景:
角色介绍:
简单实现:
package com.mabibin.eg; import java.util.ArrayList; public class WordDocument implements Cloneable { private String mText ; private ArrayList<String> mImages = new ArrayList<String>() ; public WordDocument() { } @Override protected Object clone(){ WordDocument doc; try { doc = (WordDocument) super.clone(); doc.setmText(this.getmText()) ; doc.setmImages(this.getmImages()) ; return doc ; } catch (CloneNotSupportedException e) { e.printStackTrace(); } return null ; } public String getmText() { return mText; } public void setmText(String mText) { this.mText = mText; } public ArrayList<String> getmImages() { return mImages; } public void setmImages(ArrayList<String> mImages) { this.mImages = mImages; } public void addImage(String image){ this.mImages.add(image); } public void showDocment(){ System.out.println("***********START**********"); System.out.println("TEXT:"+mText); System.out.println("IMAGE LIST:" ); for (String imagename : mImages) { System.out.println("imageName:" +imagename); } System.out.println("***********END**********"); } }
package com.mabibin.eg; public class Client { public static void main(String[] args) { WordDocument wordDocument = new WordDocument() ; wordDocument.setmText("第一份文档"); wordDocument.addImage("图1"); wordDocument.addImage("图2"); wordDocument.addImage("图3"); wordDocument.addImage("图4"); wordDocument.showDocment(); WordDocument wordDocument2 = (WordDocument) wordDocument.clone(); wordDocument2.showDocment(); wordDocument2.setmText("第二份文档"); wordDocument2.showDocment(); wordDocument.showDocment(); } }
***********START********** TEXT:第一份文档 IMAGE LIST: imageName:图1 imageName:图2 imageName:图3 imageName:图4 ***********END********** ***********START********** TEXT:第一份文档 IMAGE LIST: imageName:图1 imageName:图2 imageName:图3 imageName:图4 ***********END********** ***********START********** TEXT:第二份文档 IMAGE LIST: imageName:图1 imageName:图2 imageName:图3 imageName:图4 ***********END********** ***********START********** TEXT:第一份文档 IMAGE LIST: imageName:图1 imageName:图2 imageName:图3 imageName:图4 ***********END**********结果看出wordDocument2是wordDocument.clone创建的,并且第一个输出wordDocument2的结果和wordDocument相等,内容是一样的,即wordDocument2是wordDocument的一个拷贝。而wordDocument2改变了文本内容之后也不会对wordDocument产生影响,保证了wordDocument的安全性。需要注意的是通过clone拷贝对象并不会执行构造对象,因此如果在构造函数里需要加一些特殊的初始化操作,在cloneable实现拷贝的时候,需要注意这个问题。
浅拷贝和深拷贝
上面的代码是一个浅拷贝(影子拷贝):这份拷贝并不是将原始文档的所有字段都重新构造了一份,而是副本文档的字段引用原始文档的字段。
影子拷贝有一个缺点就是只会单纯的指定对象,而不会创建对象,如果我们这个时候改变在任何地方改变该对象的话,其他的地方也会跟着改变,比如我们把代码这样写的话:
package com.mabibin.eg; public class Client { public static void main(String[] args) { WordDocument wordDocument = new WordDocument() ; wordDocument.setmText("第一份文档"); wordDocument.addImage("图1"); wordDocument.addImage("图2"); wordDocument.addImage("图3"); wordDocument.addImage("图4"); wordDocument.showDocment(); WordDocument wordDocument2 = (WordDocument) wordDocument.clone(); wordDocument2.showDocment(); wordDocument2.setmText("第二份文档"); wordDocument2.addImage("图5"); wordDocument2.showDocment(); wordDocument.showDocment(); } }
解决这种情况的方法就是深拷贝。
深拷贝在拷贝对象时,对象于引用型的字段也要采用拷贝的形式,而不是单纯的应用的心事。修改WordDocument代码中的clone代码如下:
try { WordDocument doc = (WordDocument) super.clone(); doc.setmText(this.getmText()) ; doc.mImages = (ArrayList<String>) this.mImages.clone(); return doc ; } catch (CloneNotSupportedException e) { e.printStackTrace(); } return null ;
这个时候再次wordDocument2中添加新的图片wordDocument就不会改变了。
为了避免操作副本影响原始对象,所以在开发中尽量使用深拷贝以减少错误。
注意: