定义:用原型实例指定创建对象的种类,并通过拷贝这些原型创新的对象
类图:
- Client:客户端用户
- Prototype:抽象类或者接口,声明具备clone能力
- ConcretePrototype:具体的原型类
使用场景:
- 类初始化需要消化非常多的资源,这个资源包括数据,硬件资源等,通过原型拷贝避免这些消耗。
- 通过new产生一个对象需要非常繁琐的数据准备或访问权限
- 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用,即保护性拷贝
实现方式:
原型模式主要用于对象的复制,它的核心是就是类图中的原型类Prototype。Prototype类需要具备以下两个条件:
- 实现Cloneable接口。在java语言有一个Cloneable接口,它的作用只有一个,就是在运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法。在java虚拟机中,只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出CloneNotSupportedException异常。
- 重写Object类中的clone方法。Java中,所有类的父类都是Object类,Object类中有一个clone方法,作用是返回对象的一个拷贝,但是其作用域protected类型的,一般的类无法调用,因此,Prototype类需要将clone方法的作用域修改为public类型。
/**
* Created by jmfstart on 2017/5/9.
* 文档类型,扮演的是ConcretePrototype角色,而cloneable是代表prototype角色
*/
public class WordDocument implements Cloneable {
//文本
private String mText;
//图片名列表
private ArrayList<String> mImages = new ArrayList<>();
public WordDocument(){
System.out.println("------------WordDocument的构造函数");
}
@Override
protected WordDocument clone(){
try {
WordDocument doc = (WordDocument) super.clone();
doc.mText = this.mText;
//对Images对象也调用clone()函数,进行深拷贝
doc.mImages = (ArrayList<String>) this.mImages.clone();
return doc;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
public String getText() {
return mText;
}
public void setText(String mText) {
this.mText = mText;
}
public ArrayList<String> getImages() {
return mImages;
}
public void addImages(String image) {
mImages.add(image);
}
public void showDocument(){
System.out.println("--------------Word Content Start--------------");
System.out.println("Text:"+mText);
System.out.println("Images List:");
for (String imageName:mImages){
System.out.println("image name :"+imageName);
}
System.out.println("--------------Word Content End--------------");
}
}
public class Client {
public static void main(String[] args){
// 1 构建文档对象
WordDocument originDoc = new WordDocument();
// 2 编辑文档,添加图片等
originDoc.setText("这是一篇文档");
originDoc.addImages("图片一");
originDoc.addImages("图片二");
originDoc.addImages("图片三");
originDoc.showDocument();
// 以原始文档为原型,拷贝一份副本
WordDocument doc2 = originDoc.clone();
doc2.showDocument();
// 修改文档副本,不会影响原始文档
doc2.setText("这是修改过的Doc2文本");
doc2.addImages("nihao.jpg");
doc2.showDocument();
originDoc.showDocument();
}
}
使用时注意事项
原型模式是非常简单的一个模式,它的核心问题就是对原始对象进行拷贝,在这个模式的使用过程中需要注意的就是:深、浅拷贝的问题。为了减少错误,建议在使用该模式时尽量使用深拷贝,避免操作副本时影响原始对象的问题。
优点
原型模式是在内存中二进制流的拷贝,要比直接new一个对象性能好的多,特别是在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。
缺点
这既是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的,在实际开发中应该注意这个潜在的问题,优点就是减少了约束,缺点也是减少了约束,需要大家在实际应用时考虑。