网站程序优化,网站建设网络公关,网站开发素材代码,wordpress怎样增加移动端一、介绍
原型模式是一个创建型的模式。原型二字表明了该模型应该有一个样板实例#xff0c;用户从这个样板对象中复制出一个内部属性一致的对象#xff0c;这个过程也就是我们俗称的“克隆”。被复制的实例就是我们所称的“原型”#xff0c;这个原型也是可定制的。原型模…一、介绍
原型模式是一个创建型的模式。原型二字表明了该模型应该有一个样板实例用户从这个样板对象中复制出一个内部属性一致的对象这个过程也就是我们俗称的“克隆”。被复制的实例就是我们所称的“原型”这个原型也是可定制的。原型模型多用于创建复杂的或者构造耗时的实例因为这种情况下复制一个已经存在的实例可使程序运行更高效。
二、定义
用原型实例指定创建对象的种类并通过拷贝这些原型创建新的对象。
三、使用场景
1类初始化需要消耗非常多的资源这个资源包括数据、硬件资源等通过原型拷贝避免这些消耗。2通过new产生一个对象需要非常繁琐的数据准备或访问权限这时可以使用原型模式。3一个对象需要提供给其他对象访问而且各个调用者可能都需要修改其值时可以考虑使用原型模式拷贝多个对象供调用者使用即保护性拷贝。
需要注意的是通过实行Cloneable接口的原型模式在调用clone函数构造实例时并不一定比通过new操作速度快只有当通过new构造对象较为耗时或者说成本较高时通过clone方法才能够获得效率上的提升。因此在使用Cloneable时需要考虑构建对象的成本以及做一些效率上的测试。当然实现原型模式也不一定非要实现Cloneable接口也有其他的实现方式这里将会对这些一一说明。
四、原型模型的UML类图 图中角色介绍
Client客户端用户。Prototype抽象类或者接口声明具备clone能力。ConcretePrototype具体的原型类。
五、原型模式的简单实现
下面以简单的文档拷贝为例来演示一下简单的原型模式我们在这个例子中首先创建了一个文档对象即WordDocument这个文档中含有文字和图片。用户经过了长时间的内容编辑后打算对该文档做进一步的编辑但是这个编辑后的文档是否会被采用还不确定因此为了安全起见用户需要将当前文档拷贝一份然后再在文档副本上进行修改这与《Effective Java》一书中提到的保护性拷贝有些类似如此这个原始文档就是我们上述所说的样板实例也就是将要被“克隆”的对象我们成为原型
示例代码
/*** 文档类型扮演的是ConcretePrototype角色而cloneable是代表prototype角色*/
public class WordDocument implements Cloneable {//文本private String mText;//图片名列表private ArrayListString mImages new ArrayListString();public WordDocument(){System.out.println(-------- WordDocument构造函数 --------);}public String getText(){return this.mText;}public void setText(String text){this.mText text;}public ArrayListString getImages(){return this.mImages;}public void setImages(ArrayListString images){this.mImages images;}public void addImage(String img){this.mImages.add(img);}/*** 打印文档*/public void showDocument(){System.out.println(-------- Word Content Start --------);System.out.println(Text : this.mText);System.out.println(Images List : );for(String image : mImages){System.out.println(image name : image);}System.out.println(-------- Word Content End --------);}Overrideprotected WordDocument clone(){try{WordDocument doc (WordDocument)super.clone();doc.mText this.mText;doc.mImages this.mImages;return doc;}catch(Exception e){}return null;}
}
执行方法 public static void main(String[] args) throws IOException {//1.构建文档对象WordDocument originDoc new WordDocument();//2.编辑文档添加图片等originDoc.setText(这是一篇文档);originDoc.addImage(图片一);originDoc.addImage(图片二);originDoc.addImage(图片三);originDoc.showDocument();//以原始文档为原型拷贝一份副本WordDocument doc2 originDoc.clone();doc2.showDocument();//修改文档副本doc2.setText(这是修改过的Doc2文本);doc2.addImage(这是新添加的图片);originDoc.showDocument();doc2.showDocument();}
执行结果
-------- WordDocument构造函数 --------
//originDoc
-------- Word Content Start --------
Text : 这是一篇文档
Images List :
image name : 图片一
image name : 图片二
image name : 图片三
-------- Word Content End --------//doc2
-------- Word Content Start --------
Text : 这是一篇文档
Images List :
image name : 图片一
image name : 图片二
image name : 图片三
-------- Word Content End --------//副本修改后originDoc
-------- Word Content Start --------
Text : 这是一篇文档
Images List :
image name : 图片一
image name : 图片二
image name : 图片三
image name : 这是新添加的图片
-------- Word Content End --------//副本修改后doc2
-------- Word Content Start --------
Text : 这是修改过的Doc2文本
Images List :
image name : 图片一
image name : 图片二
image name : 图片三
image name : 这是新添加的图片
-------- Word Content End --------
这里我们发现通过修改doc2后只是影响了originDoc的mImages而没有改变mText。
六、浅拷贝和深拷贝
上述原型模式的实现实际上只是一个浅拷贝也称影子拷贝这份拷贝实际上并不是将原始的文档的所有字段都重新构造了一份而是副本文档的字段引用原始文档的字段如下图 细心的读者可能从上面的结果中发现最后两个文档信息输出是一致的。我们在doc2添加了一张图片但是同时也显示在originDoc中这是怎么回事呢学习过C的读者都会有比较深刻的体会这是因为上文中WordDocument的clone方法中只是简单的进行了浅拷贝引用类型的新对象doc2.mImages只是单纯的指向了this.mImages引用并没有重新构造一个mImages对象然后将原始文档中的图片添加到新的mImages对象中这样就导致doc2.mImages与原始文档中的是同一个对象因此修改了其中一个文档中的图片另一个文档也会受影响。那么如何解决这个问题呢答案就是采用深拷贝即在拷贝对象时对于引用型的字段也要采用拷贝的形式而不是单纯引用的形式。
clone方法修改如下(其他不变) Overrideprotected WordDocument clone(){try{WordDocument doc (WordDocument)super.clone();doc.mText this.mText;//对mImages对象也调用clone()函数进行深拷贝doc.mImages (ArrayListString)this.mImages.clone();return doc;}catch(Exception e){}return null;}
修改后在执行上述代码的结果是
-------- WordDocument构造函数 --------
//originDoc
-------- Word Content Start --------
Text : 这是一篇文档
Images List :
image name : 图片一
image name : 图片二
image name : 图片三
-------- Word Content End --------//doc2
-------- Word Content Start --------
Text : 这是一篇文档
Images List :
image name : 图片一
image name : 图片二
image name : 图片三
-------- Word Content End --------//副本修改后originDoc
-------- Word Content Start --------
Text : 这是一篇文档
Images List :
image name : 图片一
image name : 图片二
image name : 图片三
-------- Word Content End --------//副本修改后doc2
-------- Word Content Start --------
Text : 这是修改过的Doc2文本
Images List :
image name : 图片一
image name : 图片二
image name : 图片三
image name : 这是新添加的图片
-------- Word Content End --------
可以看出现在互不影响这个叫做深拷贝。
接着上面的疑问其实String类型在浅拷贝时和引用类型一样没有单独复制而是引用同一地址因为String没有实现cloneable接口也就是说只能复制引用。这里我们可以查看源码可以看到而ArrayList实现了cloneable接口但是当修改其中的一个值的时候会新分配一块内存用来保存新的值这个引用指向新的内存空间原来的String因为还存在指向他的引用所以不会被回收这样虽然是复制的引用但是修改值的时候并没有改变被复制对象的值。
所以在很多情况下我们可以把String在clone的时候和基本类型做相同的处理只是在equals时注意一些就行了。
原型模式是非常简单的一个模式它的核心问题就是对原始对象进行拷贝在这个模式的使用过程中需要注意的一点就是深、浅拷贝的问题。在开发过程中为了减少错误作者建议使用该模式时尽量使用深拷贝避免操作副本时影响原始对象的问题。
七、Android源码中的原型模式
示例代码 Uri uri Uri.parse(smsto:110);Intent intent new Intent(Intent.ACTION_SEND,uri);intent.putExtra(sms_body, The SMS text);//克隆Intent intent2 (Intent)intent.clone();startActivity(intent2);
八、总结
原型模式本质上就是对象的拷贝与C中的拷贝构造函数有些类似它们之间容易出现的问题也都是深拷贝、浅拷贝。使用原型模式可以解决构建复杂对象的资源消耗问题能够在某些场景下提升创建对象的效率。
优点
1原型模式是在内存中二进制流的拷贝要比直接new一个对象性能好很多特别是要在一个循环体内产生大量对象时原型模式可能更好的体现其优点。2还有一个重要的用途就是保护性拷贝也就是对某个对象对外可能是只读的为了防止外部对这个只读对象的修改通常可以通过返回一个对象拷贝的形式实现只读的限制。
缺点
1这既是它的优点也是缺点直接在内存中拷贝构造函数是不会执行的在实际开发中应该注意这个潜在问题。优点是减少了约束缺点也是减少了约束需要大家在实际应用时考虑。2通过实现Cloneable接口的原型模式在调用clone函数构造实例时并不一定比通过new操作速度快只有当通过new构造对象较为耗时或者说成本较高时通过clone方法才能够获得效率上的提升。