原型模式定义:
用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
使用场景:
1. 类初始化需要消化非常多的资源,这个资源包括数据,硬件资源等,通过原型拷贝避免这些消耗。
2. 通过new产生一个对象需要非常繁琐的数据准备或者访问权限,这是可以使用·1原型模式
3. 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用,即保护性拷贝。
UML类图如下:
package com.yf.pattern.prototype;
import java.util.ArrayList;
/**
File: WordDocument.java
Description: TODO
@author
@date 2016年12月28日 上午9:45:01
@version 1.0
**/
/**
*
* WordDocument,即ConcretePrototype的角色
* Clonealbe代表Prototype角色
*/
public class WordDocument implements Cloneable{
private String mText;
private ArrayList<String> mImages = new ArrayList<String>();
public WordDocument(){
System.out.println("------WordDocument构造函数------");
}
@Override
protected WordDocument clone() {
try{
WordDocument doc = (WordDocument) super.clone();
doc.mText = this.mText;
doc.mImages = this.mImages;
return doc;
}catch(Exception 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 addImage(String img) {
this.mImages.add(img);
}
public void showDocument(){
System.out.println("------ Word Content Start ------");
System.out.println("Text: " + mText);
System.out.println("Images List: ");
for(String name: mImages){
System.out.println("Image name: " + name);
}
System.out.println("------ Word Content End ------");
}
}
运行结果如下:
------WordDocument构造函数------
------ Word Content Start ------
Text: 这是一篇文档
Images List:
Image name: 图片1
Image name: 图片2
Image name: 图片3
------ Word Content End ------
------ Word Content Start ------
Text: 这是一篇文档
Images List:
Image name: 图片1
Image name: 图片2
Image name: 图片3
------ Word Content End ------
------ Word Content Start ------
Text: 这是一个修改过的Doc2文本
Images List:
Image name: 图片1
Image name: 图片2
Image name: 图片3
------ Word Content End ------
------ Word Content Start ------
Text: 这是一篇文档
Images List:
Image name: 图片1
Image name: 图片2
Image name: 图片3
------ Word Content End ------
上述运行结果表明,clone拷贝对象的时候,不会运行构造函数。
浅拷贝和深拷贝
对于引用对象,如果仅仅使用
doc.mImages = this.mImages;
则属于浅拷贝;
那样上例中,如果修改doc2的引用对象,例如doc2.addImage()会同时修改doc2和originDoc这2个对象,因为doc2和originDoc都指向同一个引用对象。
如果在拷贝对象时,对于引用型的字段也采用拷贝的形式,则属于深拷贝,例如
doc.mImages = (ArrayList<String>)this.mImages.clone();
这样修改doc2,就完全不会影响originDoc
结论:在使用过程中尽量使用深拷贝,避免出现操作副本影响原始对象的问题。
clone方法可以用super.clone,也可以用new,两者区别在于:
根据构造对象的成本来决定,如果构造对象的成本比较高或者构造较为麻烦,则使用clone函数效率较高,否则可以使用new的形式