以文档复制为例记录。
1. 具体原型 及原型角色
import android.util.Log;
import androidx.annotation.NonNull;
import java.util.ArrayList;
import java.util.List;
/**
* 文档类型,扮演的是ConcretePrototype角色,而Cloneable 代表的是prototype 角色
*/
public class WordDocument implements Cloneable {
//文本
private String mText;
//图片列表, 使用ArrayList 是因为它实现了Cloneable接口, 可以调用其clone()方法, 而接口List 则没有实现Cloneable
private ArrayList<String> mImages = new ArrayList<String>();
public WordDocument() {
Log.d("WordDocument", "----------- WordDocument 构造函数");
}
@NonNull
@Override
public WordDocument clone() throws CloneNotSupportedException {
try {
WordDocument doc = (WordDocument) super.clone();
doc.mText = this.mText;
//doc.mImages = this.mImages; //浅拷贝,复制的是引用,会修改原来的
doc.mImages = (ArrayList<String>) this.mImages.clone();//深拷贝,对非基本类型进行深拷贝
return doc;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public String getText() {
return mText;
}
public void setText(String mText) {
this.mText = mText;
}
public List<String> getImages() {
return mImages;
}
public void addImage(String image) {
this.mImages.add(image);
}
public void showDocument(){
Log.d("WordDocument", "----------- WordDocument content start");
Log.d("WordDocument", "Text: " + mText);
Log.d("WordDocument", "Image List: ");
for(String imageName: mImages) {
Log.d("WordDocument", "Image name: " + imageName);
}
Log.d("WordDocument", "----------- WordDocument content end");
}
}
这里需要注意浅拷贝和深拷贝,
//doc.mImages = this.mImages; //浅拷贝,复制的是引用,会修改原来的
doc.mImages = (ArrayList<String>) this.mImages.clone();//深拷贝,对非基本类型进行深拷贝
其中,例如 Android 中的Bundle 对象,
如果 Bundle extra1 = new Bundle();
Bundle extra2 = extra1;
则表示 extra2 会使用和extra1一样的引用, 当同时操作 Bundle的成员变量 map 相关时,则会抛出异常 (ConcurrentModificationException java.util.ConcurrentModificationException:)
解决方法是使用 clone 复制一份, 即 extra2 = extra1.clone() ; // 其实也是浅拷贝,不过它会创建新的map
/**
* A mapping from String keys to various {@link Parcelable} values.
*
* @see PersistableBundle
*/
public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
static {
EMPTY = new Bundle();
EMPTY.mMap = ArrayMap.EMPTY;
/**
* Clones the current Bundle. The internal map is cloned, but the keys and
* values to which it refers are copied by reference.
*/
@Override
public Object clone() {
return new Bundle(this);
}
/**
* Make a deep copy of the given bundle. Traverses into inner containers and copies
* them as well, so they are not shared across bundles. Will traverse in to
* {@link Bundle}, {@link PersistableBundle}, {@link ArrayList}, and all types of
* primitive arrays. Other types of objects (such as Parcelable or Serializable)
* are referenced as-is and not copied in any way.
*/
public Bundle deepCopy() {
Bundle b = new Bundle(false);
b.copyInternal(this, true);
return b;
}
2. 测试代码
@Test
fun testPrototype() {
Log.d(TAG, "====================Prototype====================")
//1.构建文件对象
val originDoc = WordDocument()
//2.编辑文本及添加图片
originDoc.text = "这是一篇文档"
originDoc.addImage("图片1")
originDoc.addImage("图片2")
originDoc.addImage("图片3")
originDoc.showDocument()
//以原始文档为原型,拷贝一份副本
val doc2 = originDoc.clone()
// 修改文档副本,不会影响原来的文档
doc2.text = "这是修改过的Doc2文本"
doc2.showDocument()
//确认原始文档
originDoc.showDocument()
}
3. 输出结果
17:20:25.386 D/DesignPattern: ====================Prototype====================
17:20:25.386 D/WordDocument: ----------- WordDocument 构造函数
17:20:25.386 D/WordDocument: ----------- WordDocument content start
17:20:25.386 D/WordDocument: Text: 这是一篇文档
17:20:25.386 D/WordDocument: Image List:
17:20:25.387 D/WordDocument: Image name: 图片1
17:20:25.387 D/WordDocument: Image name: 图片2
17:20:25.387 D/WordDocument: Image name: 图片3
17:20:25.387 D/WordDocument: ----------- WordDocument content end
17:20:25.387 D/WordDocument: ----------- WordDocument content start
17:20:25.387 D/WordDocument: Text: 这是修改过的Doc2文本
17:20:25.387 D/WordDocument: Image List:
17:20:25.387 D/WordDocument: Image name: 图片1
17:20:25.387 D/WordDocument: Image name: 图片2
17:20:25.387 D/WordDocument: Image name: 图片3
17:20:25.387 D/WordDocument: Image name: 新的图片.jpg
17:20:25.388 D/WordDocument: ----------- WordDocument content end
17:20:25.388 D/WordDocument: ----------- WordDocument content start
17:20:25.388 D/WordDocument: Text: 这是一篇文档
17:20:25.388 D/WordDocument: Image List:
17:20:25.388 D/WordDocument: Image name: 图片1
17:20:25.388 D/WordDocument: Image name: 图片2
17:20:25.388 D/WordDocument: Image name: 图片3
17:20:25.388 D/WordDocument: ----------- WordDocument content end
由此看出, 复制的文档中, 添加了一张图片 ("新的图片.jpg"), 并不会影响原始的文档, 这是使用了深拷贝