文章目录
- 1、原型模式介绍
- 2、使用场景
- 3、原型模式UML 类图
- 4、原型模式的简单实现
- 1)文件结构
- 2)WordDocumentClass.java 文件
- 3)ClientActivity.java 文件
- 5、 浅拷贝 和 深拷贝
1、原型模式介绍
1)该模式有一个样板实例,用户从这个样板对象中复制一个内部属性一致的对象。
2)复制的实例就是我们的原型。
3)原型多用于创建复杂的或者构造耗时的实例。
4)复制一个已经存在的实例可以使程序更高效。
2、使用场景
1)初始化一个类需要消耗很多的资源,这个资源包括数据、硬件等,通过原型复制避免这些消耗。
2)初始化需要非常多的数据准备或者权限访问
3)一个对象可能提供给其他对象访问,而且各个调用都需要修改。
3、原型模式UML 类图
1)Client: 客户端用户
2)Prototype: 抽象类或接口,声明具备clone 能力
3)ConcretePrototype: 具体的原型类
4、原型模式的简单实现
就以文档拷贝为例来演示一下简单的原型模式的基本结构和思路。
1)首先创建 一个文档对象 WordDocument,这个文档包含 文字和图片
2)我们对内容编辑时先复制一个,将前文档备份,在文档副本上进行修改。
1)文件结构
2)WordDocumentClass.java 文件
package com.example.menglux.worddocument;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import java.util.ArrayList;
import java.util.List;
public class WordDocumentClass implements Cloneable {
//文本
private String mText;
//图片名列表
private ArrayList<String> mImages = new ArrayList<String>();
public WordDocumentClass() {
System.out.println("```````WordDocument 构造函数········");
}
@Override
protected WordDocumentClass clone() {
try {
WordDocumentClass doc = (WordDocumentClass) super.clone();
doc.mText = this.mText;
doc.mImages = this.mImages;
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 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 imfName : mImages) {
System.out.println(" image name: " + imfName);
}
System.out.println("``````````Word Contet End````````");
}
}
3)ClientActivity.java 文件
package com.example.menglux.worddocument;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
/**
* Created by menglux on 9/10/2018.
*/
public class ClientActivity extends AppCompatActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_word_document);
//构建文档对象
WordDocumentClass originDoc = new WordDocumentClass();
//编辑文档 添加图片
originDoc.setText("这是一篇文档");
originDoc.addImage("图爿1");
originDoc.addImage("图片2");
originDoc.addImage("图片3");
originDoc.showDocument();
//以原始文档为原型,拷贝一份副本
WordDocumentClass doc2 = originDoc.clone();
doc2.showDocument();
//修改文档副本,不会影响原始文档
doc2.setText("这是修改过的 Doc2 文档");
doc2.showDocument();
}
}
打印出来的log:
(1)我们可以看到,doc2是通过 originDoc.clone()创建的,并且doc2 第一次输出的和orginDoc是一样的。
(2)当我们修改了doc2 里的 文本之后, originDoc 的文本 并没有被改变。
5、 浅拷贝 和 深拷贝
1)上述原型 模式实际上 只是一个浅拷贝 ,也称为影子拷贝。
2)它并没有将所有字段重新构造一份,而是副本文档引用原始文档字段。
我们可以看到 A 引用B 就是说两个对象 指向同一个地址,当修改 A 时,B 也会改变。 B 修改时 A 同样 也会改变。
3) 我们 将 clientActivity .java 稍作修改
package com.example.menglux.worddocument;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
/**
* Created by menglux on 9/10/2018.
*/
public class ClientActivity extends AppCompatActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_word_document);
//构建文档对象
WordDocumentClass originDoc = new WordDocumentClass();
//编辑文档 添加图片
originDoc.setText("这是一篇文档");
originDoc.addImage("图爿1");
originDoc.addImage("图片2");
originDoc.addImage("图片3");
originDoc.showDocument();
//以原始文档为原型,拷贝一份副本
WordDocumentClass doc2 = originDoc.clone();
doc2.showDocument();
//修改文档副本,不会影响原始文档
doc2.setText("这是修改过的 Doc2 文档");
doc2.addImage("哈哈.jpg");
doc2.showDocument();
originDoc.showDocument();
}
}
我们看 打印的log:
我们可以看到最后两个文档的输出信息:
(1)对于 图片的 名称 是一样的,都添加了 哈哈.jpg
(2)上面的字符串 标题没有被改变,是因为 它并不是一个对象,是一个值类型。不是一个引用类型。
(3)引用对象的doc2只是单纯的指向this.image,并没有重新构造一个mImages对象。
(4)要解决这类修改 附件,原件不被修改,需要进行深度拷贝。
4)深度拷贝
我们 对 WordDocumentClass.java 的克隆函数进行稍微修改
@Override
protected WordDocumentClass clone() {
try {
WordDocumentClass doc = (WordDocumentClass) super.clone();
doc.mText = this.mText;
// doc.mImages = this.mImages;
// 对 mImages 对象也调用clone()函数, 进行深拷贝
doc.mImages = (ArrayList<String>) this.mImages.clone();
return doc;
} catch (Exception e){
e.printStackTrace();
}
return null;
}
修改之后,doc.mImages 指向this.mImages的一份拷贝,而不是this.mImages 本身。这样在doc2添加图片时并不会影响originDoc。运行效果看log:
我们可以看到修改的doc2 出现了添加的 哈哈.jpg, origin 并没有出现添加的 哈哈.jpg
原型模式是比较简单的模式,适用于初始化对象消耗比较大的情况。
要考虑 深 浅 的拷贝问题。
文献参考:
Android 源码设计模式解析与实战 第二版
本人郑重声明,本博客所编文章、图片版权归权利人持有,本博只做学习交流分享所用,不做任何商业用途。访问者可將本博提供的內容或服务用于个人学习、研究或欣赏,不得用于商业使用。同時,访问者应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人的合法权利;如果用于商业用途,须征得相关权利人的书面授权。若文章、图片的原作者不愿意在此展示內容,请及时通知在下,將及时予以刪除。