一、原型模式
原型模式与构造器模式、单例模式、工厂方法模式、抽象工厂模式一样,都属于创建型模式。原型模式理解起来,相对简单,来看下其定义:
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式的实例的拷贝包括浅复制和深复制:
浅复制:将一个对象复制后,其基本数据类型的变量都会重新创建,而引用类型的变量指向的还是原对象所指向的,也就是指向的内存堆地址没变。
深复制:将一个对象复制后,不论是基本数据类型还是引用类型,都是重新创建的。
从以上可以看出,浅复制中的引用类型只是复制了变量的值,其地址仍然没变;而深复制完全复制了变量,复制后变量地址会有所变化。
有一个消息类,其属性及方法声明如下:
public class Message implements Cloneable, Serializable { private String name; //消息名称 private String size; //消息大小 private int type; //消息类型 private Date date; //创建日期 public static final int TEXT = 0x01; public static final int PIC = 0x02; public static final int VIDEO = 0x03; public static final int MIX = 0x04; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSize() { return size; } public void setSize(String size) { this.size = size; } public int getType() { return type; } public void setType(int type) { this.type = type; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public Message clone() throws CloneNotSupportedException { return (Message) super.clone(); } public Message deepClone() throws CloneNotSupportedException, IOException, ClassNotFoundException { //把对象写入到字节流中 ByteArrayOutputStream baos =new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(this); //把字节流转化为对象 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); return (Message) ois.readObject(); } @Override public String toString() { String tos = "name[" + name + "],size[" + size + "],type[" + type + "],date[" + date + "]"; return tos; } public static void main(String[] a) { Message msg = new Message(); msg.setName("好友消息"); msg.setSize("123KB"); msg.setType(Message.TEXT); msg.setDate(new Date()); System.out.println("msg:" + msg.toString()); try { Message cloneMsg = msg.clone(); System.out.println("msg:" + msg.toString()); System.out.println("cloneMsg:" + cloneMsg.toString()); System.out.println(cloneMsg.getDate() == msg.getDate()); System.out.println(cloneMsg.getName() == msg.getName()); System.out.println(cloneMsg.getType() == msg.getType()); } catch (Exception e) { e.printStackTrace(); } }}
通过实现Cloneable接口,java默认的实现方式是浅复制,而非深复制。由于Object并没有实现Cloneable接口,所以子类必须实现Cloneable,并调用基类的clone方法才能实现浅复制。
要实现深复制,Message类需要实现序列化,通过对象流与字节流之间的转化,达到深复制的目的。
Message类中的deepClone方法就是深复制的实现。
以上main方法的执行结果如下:
msg:name[好友消息],size[123KB],type[1],date[Tue Apr 05 17:47:56 CST 2016]msg:name[好友消息],size[123KB],type[1],date[Tue Apr 05 17:47:56 CST 2016]cloneMsg:name[好友消息],size[123KB],type[1],date[Tue Apr 05 17:47:56 CST 2016]truetruetrue
说明,浅复制只是复制了引用类型的值,并没有改变其地址,指向的仍然是原对象的变量地址。
在main方法中调用deepClone方法:
public static void main(String[] a) { ...... Message cloneMsg = msg.deepClone(); ...... }
最后的输出结果如下:
msg:name[好友消息],size[123KB],type[1],date[Tue Apr 05 17:54:39 CST 2016]msg:name[好友消息],size[123KB],type[1],date[Tue Apr 05 17:54:39 CST 2016]cloneMsg:name[好友消息],size[123KB],type[1],date[Tue Apr 05 17:54:39 CST 2016]falsefalsetrue
可以看出,深复制下,引用类型变成了完全的复制,所有的引用类型地址都变化了。
二、jdk中的原型模式
jdk中大部分类都提供了克隆的方法,比如Date类:
public class Date implements java.io.Serializable, Cloneable, Comparable<Date>{ public Object clone() { Date d = null; try { d = (Date)super.clone(); if (cdate != null) { d.cdate = (BaseCalendar.Date) cdate.clone(); } } catch (CloneNotSupportedException e) {} // Won't happen return d; }}
本文由慕课网 ifynn原创,转载请注明!