文档是我们在计算机上记录文字等一个工具,通常一份文档有一个大标题,也有许多个副标题。文档的复制拷贝也很常见,那么怎么在程序设计中运用原型模式来模拟文档的复制呢?
首先,通过UML图大概了解一下原型模式吧:
Client:客户端类
Prototype:抽象类或接口,实现了Cloneable接口
ConcretePrototype:具体的原型类
既然需要模拟文档复制,那么就需要先建立一个文档:
//Docment相当于ConcretePrototype,而Cloneable接口相当于Prototype
public class Document implements Cloneable{
//主标题
private String title;
//所有副标题
private ArrayList<String> subTitles = new ArrayList<>();
@Override
protected Document clone() throws CloneNotSupportedException {
Document mNewspaper = (Document) super.clone();
mNewspaper.title = title;
mNewspaper.subTitles = subTitles;
return mNewspaper;
}
//添加副标题
public void addSubTitle(String content) {
subTitles.add(content);
}
//设置主标题
public void setTitle(String title) {
this.title = title;
}
//文档内容
public String getDocText() {
return title + " " + subTitles.toString();
}
}
然后需要一个客户端来进行复制:
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Document doc = new Document();
doc.setTitle("标题");
doc.addSubTitle("副标题1");
doc.addSubTitle("副标题2");
doc.addSubTitle("副标题3");
System.out.println("原文档:" + doc.getDocText());
Document docCloning = doc.clone();
System.out.println("复制的文档:" + docCloning.getDocText());
}
}
结果为:
原文档:标题 [副标题1, 副标题2, 副标题3]
复制的文档:标题 [副标题1, 副标题2, 副标题3]
这就是原型模式的实现,但是却会存在下列的问题,将代码修改一下:
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Document doc = new Document();
doc.setTitle("标题");
doc.addSubTitle("副标题1");
doc.addSubTitle("副标题2");
doc.addSubTitle("副标题3");
System.out.println("原文档:" + doc.getDocText());
Document docCloning = doc.clone();
System.out.println("复制的文档:" + docCloning.getDocText());
System.out.println();
//克隆的对象添加一个副标题,之后输出克隆的和原来的DOC内容
docCloning.addSubTitle("副标题4");
System.out.println("复制的文档:" + docCloning.getDocText());
System.out.println("原文档:" + doc.getDocText());
}
}
结果为:
原文档:标题 [副标题1, 副标题2, 副标题3]
复制的文档:标题 [副标题1, 副标题2, 副标题3]复制的文档:标题 [副标题1, 副标题2, 副标题3, 副标题4]
原文档:标题 [副标题1, 副标题2, 副标题3, 副标题4]
会发现原来的文档的副标题也修改了,这就引出了克隆的知识点:浅克隆与深克隆。
上述的克隆方式即为浅克隆,虽然克隆出了一个新的文档,但是他们对于subTitles的引用还是指向了同一个对象。要想避免出现这种问题,则需要使用深克隆,方法也很简单:
@Override
protected Document clone() throws CloneNotSupportedException {
Document mNewspaper = (Document) super.clone();
mNewspaper.title = title;
//将引用的字段subTitles也进行克隆
mNewspaper.subTitles = (ArrayList<String>) subTitles.clone();
return mNewspaper;
}
结果为:
复制的文档:标题 [副标题1, 副标题2, 副标题3, 副标题4]
原文档:标题 [副标题1, 副标题2, 副标题3]
原型模式的应用相对简单,只不过需要注意到什么时候应该用浅克隆,或是深克隆。该模式适用于当需要一个相同的副本,要避免使用new来产生新对象导致资源消耗时使用。
原型模式的优缺点
- 优点
– 相对于用new产生一个对象来说,会消耗更少的资源,尤其是在循环体内。 - 缺点
-原型模式是克隆二进制流,并不会执行构造方法。