欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JAVA的23种设计模式之原型模式

程序员文章站 2022-06-13 07:55:31
...

原型模式:

  •  通过new 产生一个对象需要非常繁琐的数据准备或者访问权限,则可以使用原型模式
  • 就是Java中的克隆技术,以某个对象为原型,复制出新的对象,显然新的对象具备原型对象的特点。
  • 优势有:效率高于new 方式
  • 克隆类似于new ,但是不同于new, 使用new创建的新对象的属性是采用的默认值。克隆出的对象属性和原型对象相同。并且克隆出的新对象改变不会影响原型对象。然后在修改克隆对象的值。

原型模式实现:

  • Cloneable接口和clone方法
  • Prototype 模式中实现起来最困难的地方就是内存复制操作。所幸 JAVA中提供了clone()方法替我们做了绝大部分事情。

 

测试原型模式   浅克隆:

创建需要克隆的类:

package cn.fllday.prototype;

import java.util.Date;

/**
 * 创建需要克隆的对象。 实现原型模式
 * 如果需要克隆,就必须实现Cloneable 接口
 * @author gssznb
 *
 */
public class Sheep implements Cloneable {
	
	private String name;
	
	private Date date;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Date getDate() {
		return date;
	}

	public void setDate(Date date) {
		this.date = date;
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}

	@Override
	public String toString() {
		return "Sheep [name=" + name + ", date=" + date + "]";
	}
	
	
	
}

测试原型模式:浅克隆

package cn.fllday.prototype;

import java.util.Date;

/**
 * 测试原型模式   浅克隆
 * @author gssznb
 *
 */
public class Client01 {	
	/**
	 * 浅克隆: 直接使用clone 克隆一个对象。如果该对象中含有其他对象 比如 Date(); 如果我修改了Date的值
	 * 但是  克隆的对象和被克隆的对象都指向到了 该 Date() 对象。 所以 两个对象的Date 都会进行改变。
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		Date date = new Date(1111111111111L);
		Sheep sheep = new Sheep();
		sheep.setName("多利");
		sheep.setDate(new Date());
		Sheep clone = (Sheep) sheep.clone();
		date.setTime(55555555555L);
		System.out.println(sheep);
		System.out.println(clone);
		
	}	
}

原型模式深克隆:

创建需要深克隆的对象

package cn.fllday.prototype;

import java.util.Date;

/**
 * 创建需要克隆的对象。 实现原型模式
 * 如果需要克隆,就必须实现Cloneable 接口
 * @author gssznb
 *
 */
public class Sheep02 implements Cloneable {
	
	private String name;
	
	private Date date;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Date getDate() {
		return date;
	}

	public void setDate(Date date) {
		this.date = date;
	}
	
	/**
	 * 实现深复制  需要 重新实现clone 方法
	 * 对 该对象中的对象 执行一个clone方法 并且 设置给 需要返回的对象
	 */
	@Override
	protected Object clone() throws CloneNotSupportedException {
		Object obj = super.clone();
		Sheep02 sheep = (Sheep02) obj;
		Date clone = (Date)sheep.getDate().clone();
		sheep.setDate(clone);
		return sheep;
	}

	@Override
	public String toString() {
		return "Sheep [name=" + name + ", date=" + date + "]";
	}
	
	
	
}

测试原型模式:深克隆

package cn.fllday.prototype;

import java.util.Date;

/**
 * 原型模式 : 深复制
 * @author gssznb
 *
 */
public class Client03 {
	
	public static void main(String[] args) throws CloneNotSupportedException {
		Date date = new Date(1111111111111L);
		Sheep02 sheep = new Sheep02();
		sheep.setName("多利");
		sheep.setDate(date);
		Sheep02 clone = (Sheep02) sheep.clone();
		date.setTime(55555555555L);
		System.out.println(sheep);
		System.out.println(clone);
	}
}

通过序列化实现原型模式:

package cn.fllday.prototype;

import java.io.Serializable;
import java.util.Date;

/**
 * 创建需要克隆的对象。 实现原型模式
 * 如果需要克隆,就必须实现Cloneable 接口
 * @author gssznb
 *
 */
public class Sheep04 implements Cloneable,Serializable {
	
	private String name;
	
	private Date date;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Date getDate() {
		return date;
	}

	public void setDate(Date date) {
		this.date = date;
	}
	
	@Override
	public String toString() {
		return "Sheep [name=" + name + ", date=" + date + "]";
	}
	
	
	
}

使用序列化 实现原型模式深克隆:

package cn.fllday.prototype;

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

/**
 * 通过反序列化 实现深复制。  
 * 反序列化过来的对象 直接就是不同的对象。
 * @author gssznb
 *
 */
public class Client04 {

	public static void main(String[] args) throws IOException, ClassNotFoundException {
		Date date = new Date(555555555L);
		Sheep04 s1 = new Sheep04();
		s1.setName("多礼");
		s1.setDate(date);
		
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(bos);
		oos.writeObject(s1);
		byte[] bytes = bos.toByteArray();
		
		ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
		ObjectInputStream ois = new ObjectInputStream(bis);
		Sheep04 s2 = (Sheep04)ois.readObject();
		date.setTime(999999999999L);
		System.out.println(s1);
		System.out.println(s2);
	}
	
}

测试使用克隆和new的差距

 

package cn.fllday.prototype;

import java.util.ArrayList;
import java.util.List;

/**
 * 测试普通new 方法和 clone 方法的效率差异
 * 如果需要短时间内创建大量的对象。并且new的时间比较耗时。就可以考虑使用原型模式
 * 如果new的时间越长,那么 效率差异越来越大
 * @author gssznb
 *
 */
public class Clent05 {

	public static void main(String[] args) throws CloneNotSupportedException {
		testClone(1000);
		testNew(1000);
	}
	
	
	public static void testNew(int size) {
		long start = System.currentTimeMillis();
		for (int i = 0; i < size; i++) {
			new Apple();
		}
		long end = System.currentTimeMillis();
		System.out.println("使用new的方式:" + (end - start));
	}
	
	public static void testClone(int size) throws CloneNotSupportedException {
		Apple apple = new Apple();
		long start = System.currentTimeMillis();
		List<Apple> apples = new ArrayList<>();
		for (int i = 0; i < size; i++) {
			Apple clone = (Apple) apple.clone();
			apples.add(clone);
		}
		
		long end = System.currentTimeMillis();
		System.out.println("使用clone的方式:" + (end - start));
	}
	
	
}


class Apple implements Cloneable{
	String name;
	
	public Apple() {
		// TODO Auto-generated constructor stub
		try {
            // 使用sleep沉睡十毫秒。 模拟创建对象比较复杂
			Thread.sleep(10);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		return super.clone();
	}
}

测试结果:

使用clone的方式:0
使用new的方式:10608

哈哈 就是这么快