设计模式笔记之原型模式的使用

<其它设计模式介绍及案例源码下载 >

简介:原型模式(Prototype Pattern)是用于创建重复的对象,并且与重新new对象相比较,性能更高。这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。

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

优点: 1、性能提高。 2、逃避构造函数的约束。

缺点: 1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。 2、必须实现 Cloneable 接口。

使用场景: 1、资源优化场景。 2、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。 3、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。 4、一个对象多个修改者的场景。5、在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与 Java 融为浑然一体,大家可以随手拿来使用。

实例分析:

方案一(通过实现Cloneable接口实现深浅复制,代码如下):

public class MainClassCloneAble implements Cloneable{

	String name;
	AccompanyCloneable acA;
	
	
	public MainClassCloneAble() {
		super();
		// TODO Auto-generated constructor stub
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public AccompanyCloneable getAcA() {
		return acA;
	}
	public void setAcA(AccompanyCloneable acA) {
		this.acA = acA;
	}
	
	
	@Override
	public String toString() {
		return "MainClass [name=" + name + ", acA=" + acA + "]";
	}
	@Override
	public Object clone()  {
		MainClassCloneAble mc=null;
		try {
			mc=(MainClassCloneAble) super.clone();
			//这个语句不能缺,否则即使MainClass的引用属性对应的类实现了Cloneable也是浅复制
			mc.acA=(AccompanyCloneable) acA.clone();
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return mc;
	}

}
public class AccompanyCloneable implements Cloneable {

	String name;
	String gender ;

	public AccompanyCloneable(String name, String gender) {
		super();
		this.name = name;
		this.gender = gender;
	}
	public AccompanyCloneable() {
		super();
		// TODO Auto-generated constructor stub
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	
	
	@Override
	public String toString() {
		return "AccompanyA [name=" + name + ", gender=" + gender + "]";
	}
	@Override
	protected Object clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		return super.clone();
	}

}
public class TestClass {

	public static void main(String[] args) {
		//方案一:通过实现cloneable实现深复制
		AccompanyCloneable acA=new AccompanyCloneable("aa","bb");
		MainClassCloneAble mc=new MainClassCloneAble();
		mc.setName("main");
		mc.setAcA(acA);
		MainClassCloneAble mc2=(MainClassCloneAble) mc.clone();
		mc2.getAcA().setName("dd");
		System.out.println("mc对象:"+mc);
		System.out.println("mc2对象:"+mc2);
		
	}
}

评价:这种方法实现深复制,当主类的成员变量中只有少量的引用变量时倒还好,当数量太多则会所有涉及到的随从类都要实现Cloneable接口,并且重写clone()方法,而且需要注意的是,在主类的clone()中需要对所有引用属性调用其各自的clone()方法,否则相应的引用属性无法实现深度复制,显然造成不便 。

 

方案二(通过实现Serializable接口实现深复制,代码如下):

public class MainClassSerializable implements Serializable{

	String name;
	AccompanySerializable acs;

	public MainClassSerializable() {
		super();
		// TODO Auto-generated constructor stub
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}

	public AccompanySerializable getAcs() {
		return acs;
	}
	public void setAcs(AccompanySerializable acs) {
		this.acs = acs;
	}

	@Override
	public String toString() {
		return "MainClass [name=" + name + ", acs=" + acs + "]";
	}
	
	public Object deepClone()  {
		Object o=null;
		ObjectInputStream oi=null;
		 try {
			 //将对象写到流里
			ByteArrayOutputStream bo=new ByteArrayOutputStream();
			 ObjectOutputStream oo=new ObjectOutputStream(bo);
			 oo.writeObject(this);
			 //从流里读出来
			 ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray());
			 oi=new ObjectInputStream(bi);
			 o=(oi.readObject());
			 oo.close();
			 oi.close();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		 return o;
		
	}
}
public class AccompanySerializable implements Serializable {

	String name;
	String gender ;

	public AccompanySerializable(String name, String gender) {
		super();
		this.name = name;
		this.gender = gender;
	}
	public AccompanySerializable() {
		super();
		// TODO Auto-generated constructor stub
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	
	
	@Override
	public String toString() {
		return "AccompanyA [name=" + name + ", gender=" + gender + "]";
	}
	@Override
	protected Object clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		return super.clone();
	}
	
}
public class TestClass {

	public static void main(String[] args) {

		//方案二:通过实现serializable接口将对象序列化
		AccompanySerializable acs=new AccompanySerializable("ss","ee");
		MainClassSerializable ms=new MainClassSerializable();
		ms.setName("main");
		ms.setAcs(acs);
		MainClassSerializable ms2=(MainClassSerializable) ms.deepClone();
		ms2.getAcs().setName("clone");
		System.out.println("ms对象:"+ms);
		System.out.println("ms2对象:"+ms2);
	}
}

评价:对象以及对象内部所有引用到的对象都要求是可串行化的(即实现Serializable接口),否则,就需要仔细考察那些不可串行化的对象可否设成transient,从而将之排除在复制过程之外。 对象写到一个字节流中,再从字节流中将其取出来,这样就可以重建一个新对象,该对象与母对象之间不存在引用共享的问题,也就相当于深拷贝了一个新对象,这种方法相对于通过Cloneable来说更简便。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值