1、原型模式的使用和本质、以及优势:

a、通过 new 产生一个对象需要非常繁琐的数据准备或者访问权限,则可以使用原型模式。

b、原型模式的使用就是 java 中的克隆技术,以某个对象为原型,复制出新的对象。显然,新的对象具备原型对象的特点。

c、其优势有:效率高(直接克隆,避免了重新执行构造过程步骤)。

d、克隆类似于 new, 但是不同于 new 。new 创建新的对象属性采用的是默认值。克隆出的对象的属性值完全和原型对象相同。并且克隆出来的新对象改变不会影响原型对象。(可以对克隆对象修改属性值)


2、原型模式的实现:

-  Clone 接口 和 clone 方法

-  简单的代码演示:


a、可以看到,在 Sheep 这个类中实现了 Cloneable 接口,并且覆盖了 父类 Object 的 clone() 方法。(这样就实现了浅克隆)

package com.geeklicreed.prototype;

import java.util.Date;

public class Sheep implements Cloneable{
	private Date birthday;
	private String name;
	
	public Date getBirthday(){
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		Object obj = super.clone();
		return obj;
	}

	public Sheep(Date birthday, String name) {
		super();
		this.birthday = birthday;
		this.name = name;
	}
	
	public Sheep() {
		// TODO Auto-generated constructor stub
	}
}


b、在 Client06 测试类中可以看到,克隆出来的 Sheep 对象和原来的 Sheep 对象是两个不同的对象,但是它们两的属性值相同。

package com.geeklicreed.prototype;

import java.util.Date;

public class Client {
	public static void main(String[] args) throws Exception {
		Date date = new Date(1320948723000L);
		Sheep s1 = new Sheep(date,"多利");
		Sheep s2 = (Sheep)s1.clone();
		
		System.out.println(s1);
		System.out.println(s1.getName());
		
		System.out.println(s2);
		System.out.println(s2.getName());
		
		/*输出结果为:
		com.geeklicreed.prototype.Sheep@2a139a55
		多利
		com.geeklicreed.prototype.Sheep@15db9742
		多利*/
	}
}


c、上面提到了浅克隆的问题,现在看看在 Client06 测试类修改一些代码后的输出结果。

package com.geeklicreed.prototype;

import java.util.Date;

public class Client {
	public static void main(String[] args) throws Exception {
		Date date = new Date(1320928712391L);
		Sheep s1 = new Sheep(date, "多利");
		Sheep s2 = (Sheep)s1.clone();
		
		System.out.println(s1.getBirthday());
		
		date.setTime(3302428929382983L);
		System.out.println(s1.getBirthday());
		System.out.println(s2.getBirthday());
		
		/*输出结果为:
		Thu Nov 10 20:38:32 CST 2011
		Sat Oct 23 09:16:22 CST 106619
		Sat Oct 23 09:16:22 CST 106619*/
	}
}

设计模式之原型模式prototype_prototype

  

-  注:可以看到,在测试结果中, Sheep 类的 对象 s1 和 s2 是共同使用 Date 对象,所以当 Date 对象的值发生修改时,它们两个的 brithday 属性值也就发生修改。(浅克隆只对对象进行克隆,深克隆是将对象的属性值也进行克隆操作。)


d、将 Sheep 类中的 clone 方法进行如下修改,就可以实现深克隆。

@Override
	protected Object clone() throws CloneNotSupportedException {
		Object obj = super.clone();
		Sheep sheep = (Sheep) obj;
		sheep.birthday = (Date) this.birthday.clone();//即将对象的属性也复制一遍
		return obj;
	}


package com.geeklicreed.prototype;

import java.util.Date;

public class Client {
	public static void main(String[] args) throws Exception {
		Date date = new Date(1320928712391L);
		Sheep s1 = new Sheep(date, "多利");
		Sheep s2 = (Sheep)s1.clone();
		
		System.out.println(s1.getBirthday());
		
		date.setTime(3302428929382983L);
		System.out.println(s1.getBirthday());
		System.out.println(s2.getBirthday());
		
		/*输出结果为:
		Thu Nov 10 20:38:32 CST 2011
		Sat Oct 23 09:16:22 CST 106619
		Thu Nov 10 20:38:32 CST 2011*/
	}
}


3、使用序列化和反序列化实现深克隆:

package com.geeklicreed.prototype;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;

public class Client {
	public static void main(String[] args) throws Exception {
		Date date = new Date(1320928712391L);
		Sheep s1 = new Sheep(date, "多利");
		
		//使用序列化和反序列化实现深克隆
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(bos);
		
		oos.writeObject(s1);
		byte[] by = bos.toByteArray();
		
		ByteArrayInputStream bis = new ByteArrayInputStream(by);
		ObjectInputStream ois = new ObjectInputStream(bis);
		Sheep s2 = (Sheep) ois.readObject();
		date.setTime(222324131028374983L);
		System.out.println(s1.getBirthday());
		System.out.println(s2.getBirthday());
		
		/*
		 	输出结果为:
		 	Thu Apr 03 07:26:14 CST 7047141
			Thu Nov 10 20:38:32 CST 2011
		 */
	}
}

-  注:序列化和反序列化需要在在 Sheep 类中 实现 Serializable 接口。


4、开发中的应用场景:

-  原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。

-  spring 中 bean 的创建实际上就是两种:单例模式和原型模式。(原型模式一般会和工厂模式搭配使用。)