Android 设计模式 笔记 - 原型模式

Posted 鲨鱼丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 设计模式 笔记 - 原型模式相关的知识,希望对你有一定的参考价值。

介绍:

是一个创建型的模式。原型表明该模式应该有一个样板实例,用户从这个样板对象中复制一个内部属性一致的对象,即为:克隆。原型可定制,该模式多用于创建复杂的或者构建耗时的实例,这种情况下,复制一个已经存在的实例可使程序运行的更高效。

定义:

用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。

使用场景:

  • 类初始化需要消耗非常多的资源,资源种类包括:数据资源,硬件资源。通过原型拷贝避免这些消耗。
  • 通过一个new产生一个对象需要非常繁琐的数据准备和访问权限。
  • 一个对象需要提供给其他对象访问,而且各个调用者可能需要修改其值时,可以考虑使用原型类型拷贝多个对象供调用者使用,这个叫做保护性拷贝。

角色介绍:

  • Client:客户端用户
  • Prototype:抽象类或者接口,声明具备clone能力
  • ConcretePrototype:具体的原型类

简单实现:

package com.mabibin.eg;

import java.util.ArrayList;

public class WordDocument implements Cloneable 
	private String mText ;
	private ArrayList<String> mImages = new ArrayList<String>() ;
	public WordDocument() 
		
	
	@Override
	protected Object clone()
		WordDocument doc;
		try 
			doc = (WordDocument) super.clone();
			doc.setmText(this.getmText()) ;
			doc.setmImages(this.getmImages()) ;
			return doc ;
		 catch (CloneNotSupportedException 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(ArrayList<String> mImages) 
		this.mImages = mImages;
	
	
	public void addImage(String image)
		this.mImages.add(image);
	
	
	public void showDocment()
		System.out.println("***********START**********");
		System.out.println("TEXT:"+mText);
		System.out.println("IMAGE LIST:" );
		for (String imagename : mImages) 
			System.out.println("imageName:" +imagename);
		
		System.out.println("***********END**********");
	


package com.mabibin.eg;

public class Client 
	public static void main(String[] args) 
		WordDocument wordDocument = new WordDocument() ;
		wordDocument.setmText("第一份文档");
		wordDocument.addImage("图1");
		wordDocument.addImage("图2");
		wordDocument.addImage("图3");
		wordDocument.addImage("图4");
		wordDocument.showDocment();
		
		WordDocument wordDocument2 = (WordDocument) wordDocument.clone();
		wordDocument2.showDocment();
		
		wordDocument2.setmText("第二份文档");
		wordDocument2.showDocment();
		wordDocument.showDocment();
	


结果显示为:

***********START**********
TEXT:第一份文档
IMAGE LIST:
imageName:图1
imageName:图2
imageName:图3
imageName:图4
***********END**********
***********START**********
TEXT:第一份文档
IMAGE LIST:
imageName:图1
imageName:图2
imageName:图3
imageName:图4
***********END**********
***********START**********
TEXT:第二份文档
IMAGE LIST:
imageName:图1
imageName:图2
imageName:图3
imageName:图4
***********END**********
***********START**********
TEXT:第一份文档
IMAGE LIST:
imageName:图1
imageName:图2
imageName:图3
imageName:图4
***********END**********
结果看出wordDocument2是wordDocument.clone创建的,并且第一个输出wordDocument2的结果和wordDocument相等,内容是一样的,即wordDocument2是wordDocument的一个拷贝。而wordDocument2改变了文本内容之后也不会对wordDocument产生影响,保证了wordDocument的安全性。需要注意的是通过clone拷贝对象并不会执行构造对象,因此如果在构造函数里需要加一些特殊的初始化操作,在cloneable实现拷贝的时候,需要注意这个问题。


浅拷贝和深拷贝

  • 浅拷贝

上面的代码是一个浅拷贝(影子拷贝):这份拷贝并不是将原始文档的所有字段都重新构造了一份,而是副本文档的字段引用原始文档的字段。

影子拷贝有一个缺点就是只会单纯的指定对象,而不会创建对象,如果我们这个时候改变在任何地方改变该对象的话,其他的地方也会跟着改变,比如我们把代码这样写的话:

package com.mabibin.eg;

public class Client 
	public static void main(String[] args) 
		WordDocument wordDocument = new WordDocument() ;
		wordDocument.setmText("第一份文档");
		wordDocument.addImage("图1");
		wordDocument.addImage("图2");
		wordDocument.addImage("图3");
		wordDocument.addImage("图4");
		wordDocument.showDocment();
		
		WordDocument wordDocument2 = (WordDocument) wordDocument.clone();
		wordDocument2.showDocment();
		
		wordDocument2.setmText("第二份文档");
		wordDocument2.addImage("图5");
		wordDocument2.showDocment();
		wordDocument.showDocment();
	


改动的代码是在wordDocument2上添加了一个新的图片,而现在输出wordDocument2,和wordDocument的时候就会发现wordDocument中也添加了一个新图片。

解决这种情况的方法就是深拷贝。

  • 深拷贝

深拷贝在拷贝对象时,对象于引用型的字段也要采用拷贝的形式,而不是单纯的应用的心事。修改WordDocument代码中的clone代码如下:

	try 
			WordDocument doc = (WordDocument) super.clone();
			doc.setmText(this.getmText()) ;
			doc.mImages = (ArrayList<String>) this.mImages.clone();
			return doc ;
		 catch (CloneNotSupportedException e) 
			e.printStackTrace();
		
		return null ;

如上所示,我们把doc.mImages指向了一个this.mImages的一份拷贝,而不是它本身。

这个时候再次wordDocument2中添加新的图片wordDocument就不会改变了。


为了避免操作副本影响原始对象,所以在开发中尽量使用深拷贝以减少错误。


注意:

  • 数据类型不是对象,不需要进行克隆。


以上是关于Android 设计模式 笔记 - 原型模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式 -- 原型模式 图解java对象克隆 引用拷贝浅拷贝深拷贝序列化拷贝

设计模式 -- 原型模式 图解java对象克隆 引用拷贝浅拷贝深拷贝序列化拷贝

设计模式 -- 原型模式 图解java对象克隆 引用拷贝浅拷贝深拷贝序列化拷贝

设计模式 -- 原型模式 图解java对象克隆 引用拷贝浅拷贝深拷贝序列化拷贝

粗糙分析设计模式-原型模式

粗糙分析设计模式-原型模式