原型模式–使程序运行更高效
定义 用原型实例指定创建对象的种类,并通过拷贝这些原创型创建新的对象。
原型模式的使用场景
(1) 类初始化需要消耗很多资源,这个资源包括数据、硬件资源等,通过原型拷贝避免这些消耗。
(2) 通过new产生一个对象需要非常繁琐的数据准备或者访问权限,这时可以使用原型模式
(3) 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象
供调用者使用,即保护性拷贝。
先来看一段代码,我们创建一个文档对象WorkDocument,用文档拷贝为例演示一下原型模式
public class WorkDocument implements Cloneable {
private String mText;
private ArrayList<String> mImages= new ArrayList<>();
public WorkDocument() {
System.out.println("--------------WorkDocument------------- 构造函数-----------------");
}
protected WorkDocument clone() {
try {
WorkDocument doc = (WorkDocument) 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 setmImages(String img) {
this.mImages.add(img);
}
public void showWorkDocument(){
System.out.println("--------------word content start-----------------");
System.out.println("mText"+mText);
System.out.println("Images List :");
for (String mImage : mImages) {
System.out.println("image name " + mImage);
}
System.out.println("--------------WorkDocument------------- end -----------------");
}
}
通过WorkDocument模拟了文档的基本元素,就是文字和图片WorkDocument在原型模式中扮演的角色就是ConcretePrototype
而Cloneable的角色则为Prototype。WorkDocument中的clone方法用以实现对象克隆。这个方法并不是cloneable中的方法而是
Object 中的方法。Cloneable只是一个标识接口 它表明这个类的对象是可拷贝的。如果没有实现Cloneable接口却调用了clone
方法是会抛异常的。
下面看一下客户端的调用
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
WorkDocument doc1 = new WorkDocument();
doc1.setmText("我是武功天下第一");
doc1.setmImages("xidu");
doc1.setmImages("taohuadao");
doc1.setmImages("guojing");
doc1.showWorkDocument();
WorkDocument doc2 = (WorkDocument) doc1.clone();
doc2.showWorkDocument();
doc2.setmText("改过了");
doc2.showWorkDocument();
doc1.showWorkDocument();
}
}
再看一下输出结果
--------------WorkDocument------------- 构造函数-----------------
--------------word content start-----------------
mText我是武功天下第一
Images List :
image name xidu
image name taohuadao
image name guojing
--------------WorkDocument------------- end -----------------
--------------word content start-----------------
mText我是武功天下第一
Images List :
image name xidu
image name taohuadao
image name guojing
--------------WorkDocument------------- end -----------------
--------------word content start-----------------
mText改过了
Images List :
image name xidu
image name taohuadao
image name guojing
--------------WorkDocument------------- end -----------------
--------------word content start-----------------
mText我是武功天下第一
Images List :
image name xidu
image name taohuadao
image name guojing
--------------WorkDocument------------- end -----------------
doc2是通过doc1.clone创建的并且doc2第一次输出的时候和doc1是一样的 所以doc2是doc1的一份拷贝他们内容是一样的
doc2修改的内容并不会影响doc1 这就保证了doc1的安全性。上述代码只是一份浅拷贝。
浅拷贝:Object类提供的clone方法只是拷贝对象,对象内部的数组,引用对象等不拷贝,还是指向原生对象的内部元素地址,
这种拷贝称为浅拷贝。浅拷贝中多个对象共享一个私有变量,不安全。
深拷贝:不仅拷贝对象,对象内的成员都会进行拷贝。还有一种实现方式就是通过自己写二进制流来操作对象,然后实现对象的深拷贝。
@Override
protected WorkDocument clone() {
try {
WorkDocument doc = (WorkDocument) super.clone();
doc.mText = this.mText;
//对mImages对象也调用clone函数 进行深拷贝
doc.mImages = (ArrayList<String>) this.mImages.clone();
return doc;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
原型模式是非常简单的一个模式,它的核心问题就是对原始对象进行拷贝在这个模式的使用过程中需要 注意的是 深浅拷贝问题。
在开发过程中为了减少错误建议大家使用该模式时尽量使用深拷贝