介绍
原型模式就是对象的copy。在堆中已经有了对象,我们通过克隆的方式复制一份一模一样的对象出来,这就是原型模式。因为只是内存的copy问题, 这样的话省去了创建一个对象的时间。与new不同的地方就是,通过new的方式创建的对象属性采用的是默认值。克隆出来的对象属性值完全和原型对象相同,并且克隆出来的对象发生变化一般不会影响原型对象。
实现方式
实现Cloneable接口和clone方法
示例
- 示例一
实现Cloneable接口(其实不用真的实现,这里只是给编译器一个暗示,说明该类可以被克隆)。重写clone方法,该方法是Object中的方法,涉及到内存copy,我们只需要调用父类的clone方法即可。
package com.dy.xidian; import java.util.Date; public class Sheep implements Cloneable { private String sname; private Date birthday; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } public Sheep(String sname, Date birthday) { super(); this.sname = sname; this.birthday = birthday; } public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } }
测试类
package com.dy.xidian; import java.sql.Date; public class Clinet { public static void main(String[] args) throws CloneNotSupportedException { Sheep s1 = new Sheep("羊", new Date(123456789L)); // 打印原羊的信息 System.out.println("----原羊-----"); System.out.println(s1); System.out.println(s1.getSname()); System.out.println(s1.getBirthday()); // clone出一个新对象 Sheep s2 = (Sheep) s1.clone(); // 打印克隆羊信息 System.out.println("------克隆羊------"); System.out.println(s2); System.out.println(s2.getSname()); System.out.println(s2.getBirthday()); // 更改克隆羊属性 s2.setSname("克隆羊"); s2.setBirthday(new Date(1234565433L)); System.out.println("-----对比------"); System.out.println("原羊:" + s1.getSname()); System.out.println("克隆羊:" + s2.getSname()); System.out.println("克隆羊:" + s2.getBirthday()); } }
- 示例二
package com.dy.xidian; import java.sql.Date; public class Clinet { public static void main(String[] args) throws CloneNotSupportedException { Date d = new Date(123456789L); Sheep s1 = new Sheep("羊", d); // 打印原羊的信息 System.out.println("----原羊-----"); System.out.println(s1); System.out.println(s1.getSname()); System.out.println(s1.getBirthday()); // clone出一个新对象 Sheep s2 = (Sheep) s1.clone(); // 打印克隆羊信息 System.out.println("------克隆羊------"); System.out.println(s2); System.out.println(s2.getSname()); System.out.println(s2.getBirthday()); // 更改原羊属性 d.setDate(123456789); System.out.println("-----对比------"); System.out.println("原羊:" + s1.getBirthday()); System.out.println("克隆羊:" + s2.getBirthday()); } }
可以发现当我们修改了data的值后原型和克隆的对象的值都同时发生了变化。这是因为在clone的时候,属性是完全copy。原羊的birtyday属性指向d对象,那么copy出来的birthday属性也应指向相同的对象。当d对象发生改变的时候,这两个属性的值都发生了变化。这就是所谓的浅copy。
深克隆技术
深克隆需要对属性也进行克隆
package com.dy.xidian; import java.util.Date; public class Sheep implements Cloneable { private String sname; private Date birthday; @Override protected Object clone() throws CloneNotSupportedException { Sheep s = (Sheep) super.clone(); s.birthday = (Date) this.birthday.clone(); return s; } public Sheep(String sname, Date birthday) { super(); this.sname = sname; this.birthday = birthday; } public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } }
通过反序列化实现深克隆
package com.dy.xidian; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.sql.Date; public class Clinet { public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException { Date d = new Date(123456789L); Sheep s1 = new Sheep("羊", d); // 打印原羊的信息 System.out.println("----原羊-----"); System.out.println(s1); System.out.println(s1.getSname()); System.out.println(s1.getBirthday()); 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); Sheep s2 = (Sheep) ois.readObject(); System.out.println("----克隆羊-----"); System.out.println(s2); System.out.println(s2.getSname()); System.out.println(s2.getBirthday()); d.setDate(1784567658); System.out.println("------对比------"); System.out.println("原羊: " + s1.getBirthday()); System.out.println("克隆羊: " + s2.getBirthday()); } }