Java 设计模式——原型模式(创建型设计模式)

一、什么是原型模式

所谓原型模式就是克隆模式
也可以理解为复制一个对象
克隆存在两个方向:浅克隆、深克隆
Java 设计模式——原型模式(创建型设计模式)

二、浅克隆

首先我们要知道对象中除了常量类型(int、boolean、double等)、特殊的字符串类型外还有引用类型(其实就是java类中的另外的一个java对象),其次就是要知道这些类型都是有一个内存地址指向的
最后要注意的是被克隆的对象必须Cloneable,Serializable这两个接口

那么浅克隆是什么呢?
被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。 Object类提供的方法clone只是拷贝本对象 , 其对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素地址

举例

//这里用了lombok插件,不知道的建议可以百度一下
@Data
public class Psn implements Cloneable,Serializable{
private String name;
private String age;
private Date birth;
/**
* 实现克隆的方法
 */
public Object clone() throws CloneNotSupportedException{
	return super.clone();
}
}

Test

public static void main(String[] args) throws CloneNotSupportedException {
	Date date =  new Date(1231231231231l);
	Psn psn= new Psn ();
	psn.setName("test");
	psn.setAge(18);
	psn.setBirth(date);
	System.out.println("----输出原型对象的属性------");
	System.out.println(psn);
	System.out.println(psn.getName());
	System.out.println(psn.getBirth());
	// 克隆对象
	Psn psn1 =(Psn ) psn.clone();
	// 修改原型对象中的属性
	date.setTime(123231231231l);
	System.out.println(user.getBirth());
	
	// 修改参数
	psn1.setName("test1");
	System.out.println("-------克隆对象的属性-----");
	System.out.println(psn1);
	System.out.println(psn1.getName());
	System.out.println(psn1.getBirth());
}

这里就不输出结果了,自己观察一下日志

三、深克隆

被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。

第一种方式,重写实例clone方法内的部分

		Object object = super.clone();
		// 实现深度克隆(deep clone)
		PsnCopy psnCopy = (PsnCopy)object;
		psnCopy.birth = (Date) this.birth.clone();
		return object;

第二种方式,使用序列化和反序列化
Java 设计模式——原型模式(创建型设计模式)

public static void main(String[] args) throws CloneNotSupportedException {
	Date date =  new Date(1231231231231l);
	Psn psn= new Psn ();
	psn.setName("test");
	psn.setAge(18);
	psn.setBirth(date);
	System.out.println("----输出原型对象的属性------");
	System.out.println(psn);
	System.out.println(psn.getName());
	System.out.println(psn.getBirth());
	
	//使用序列化和反序列化实现深复制
	ByteArrayOutputStream bos = new ByteArrayOutputStream();
	ObjectOutputStream    oos = new ObjectOutputStream(bos);
	oos.writeObject(psn);
	byte[] bytes = bos.toByteArray();
	
	ByteArrayInputStream  bis = new ByteArrayInputStream(bytes);
	ObjectInputStream	  ois = new ObjectInputStream(bis);
	
	//克隆好的对象!
	Psn psn1 = (Psn) ois.readObject();   
	
	// 修改原型对象的值
	date.setTime(221321321321321l);
	System.out.println(psn.getBirth());
	
	System.out.println("------克隆对象的属性-------");
	System.out.println(psn1);
	System.out.println(psn1.getName());
	System.out.println(psn1.getBirth());

四、原型模式和直接new对象方式的比较

当我们需要大量的同一类型对象的时候可以使用原型模式,下面是两种方式的性能对比:
用两种方式同时生成1000个对象


/**
 * 测试普通new方式创建对象和clone方式创建对象的效率差异!
 * 如果需要短时间创建大量对象,并且new的过程比较耗时。则可以考虑使用原型模式!
 * @author 波波烤鸭
 *
 */
public class Client4 {
	
	public static void testNew(int size){
		long start = System.currentTimeMillis();
		for(int i=0;i<size;i++){
			Psn t = new Psn();
		}
		long end = System.currentTimeMillis();
		System.out.println("new的方式创建耗时:"+(end-start));
	}
	
	public static void testClone(int size) throws CloneNotSupportedException{
		long start = System.currentTimeMillis();
		User t = new User();
		for(int i=0;i<size;i++){
			Psn temp = (Psn) t.clone();
		}
		long end = System.currentTimeMillis();
		System.out.println("clone的方式创建耗时:"+(end-start));
	}
	
	
	public static void main(String[] args) throws Exception {	
		testNew(1000);
		testClone(1000);
	}
}


class User implements Cloneable {  //用户
	public User() {
		try {
			Thread.sleep(10);  //模拟创建对象耗时的过程!
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		Object obj = super.clone();  //直接调用object对象的clone()方法!
		return obj;
	}
}

输出结果:
Java 设计模式——原型模式(创建型设计模式)
小结:通过clone的方式在获取大量对象的时候性能开销基本没有什么影响,而new的方式随着实例的对象越来越多,性能会急剧下降,所以原型模式是一种比较重要的获取实例的方式。大家应该掌握好

原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone的方法创建一个对象,然后由工厂方法提供给调用者。
• spring中bean的创建实际就是两种:单例模式和原型模式。(原型模式需要和工厂模式搭配起来)

上一篇:Java对于赋值,浅拷贝,深拷贝的原理理解以及深入思考


下一篇:java 深拷贝和浅拷贝