原型模式也可以称为克隆模式,是指用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
克隆模式的主要应用场景有两种
1.用new创建对象代价较大,如一个对象设置了非常多的属性,有非常复杂的创建过程,则不适合用new操作将所有属性和操作重复一遍。或者创建一个对象对资源开销非常大,也不适合直接用new
2.保护性拷贝,多个操作修改类对象的属性值时,为了保证数据准确性可以克隆多个对象供相应的操作调用。
实现方式:
一、浅拷贝(影子拷贝)
java中提供了Cloneable接口,需要拷贝的类只需要实现这个接口,重写里面的方法。
package com.example.clonemodel;
import java.util.ArrayList;
public class WordDocument implements Cloneable {
private String mText;
private ArrayList<String> mImages = new ArrayList<>();
public WordDocument(){
System.out.println("-------------WordDocument 构造函数----------");
}
@Override
protected WordDocument clone() throws CloneNotSupportedException {
WordDocument wordDocument = (WordDocument) super.clone();
wordDocument.mText = this.mText;
wordDocument.mImages = this.mImages;
return wordDocument;
}
public void showDocument(){
System.out.println("-------------Word content start ----------------");
System.out.println("Text : " + mText);
System.out.println("ImageList : " );
for (String imgName : mImages) {
System.out.println("image name :"+imgName);
}
System.out.println("-------------Word content end -------------------");
}
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);
}
}
package com.example.clonemodel;
public class Client {
public static void main(String[] args) {
WordDocument wordDocument = new WordDocument();
wordDocument.setmText("This is a word");
wordDocument.addImage("iamge 1");
wordDocument.addImage("iamge 2");
wordDocument.addImage("iamge 3");
wordDocument.addImage("iamge 4");
//输出原始文档
wordDocument.showDocument();
WordDocument document = null;
try {
document = wordDocument.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
//输入克隆文档
document.showDocument();
//修改新文档后输出原始文档 ,原始文档内容不受影响
document.setmText("This is a song");
document.showDocument();
wordDocument.showDocument();
}
}
上述demo中WordDocunment中对象被克隆修改,克隆出的对象属性和原始对象一致,修改克隆出的对象属性,不会影响原对象。因为可以看出克隆模式是重新创建一个对象,而不是将对象指给另一个引用而已。
二、深拷贝
上述只是浅拷贝,为什么是浅拷贝,细心的读者可能已经发现,在demo中重写的clone方法中有这么一句
wordDocument.mImages = this.mImages;
克隆对象的图片列表是直接指向原对象的列表对象,所以这个属性本质上是一个对象,只不过对象的引用不一样而已。因此可以预见在修改拷贝对象的图片列表属性时,原对象的图片列表属性也会变化。这里就不再贴代码了,只需将上述demo简单修改运行即可。
那么如何修改呢,很简单只需要将上边demo中clone方法修改一下
@Override
protected WordDocument clone() throws CloneNotSupportedException {
WordDocument wordDocument = (WordDocument) super.clone();
wordDocument.mText = this.mText;
wordDocument.mImages = (ArrayList<String>) this.mImages.clone();
return wordDocument;
}
有些读者可能会奇怪为什么一开始的demo中的mText属性,在克隆对象中修改不会影响原对象。这是java中String类的机制,这里不再赘述,有兴趣的读者可以自行学习一下,简单来说String对象是不可修改的,任何对他的修改都是新建操作。
PS:此demo摘抄自《Android源码设计模式解析与实战》