原型模式的优点:简化对象的创建,使得创建对象就像复制粘贴一样easy。
使用原型模式创建对象,一般不会调用类的构造方法,Object的clone方法是一个本地方法,直接操作内存中的二进制流,在复制大对象时,性能差别非常明显。
关于深拷贝与浅拷贝
浅拷贝 - 拷贝的是值类型以及引用类型的地址
深拷贝 - 拷贝的是值类型,对于引用类型则是创建一个新的相同的对象,并使用新对象的地址;
将普通的引用类型的变量赋值给另一个变量,既不属于深拷贝,也不属于浅拷贝!
Object的clone方法是浅拷贝,值得一提的是,根据实际测试,对于String类型的拷贝,与值类型一样,实际上是拷贝的对象。其他引用类型则拷贝的是对象的地址!
下面看关于深拷贝与浅拷贝的代码
/* * Copyright (c) 2017. Xiaomi.Co.Ltd All rights reserved */ package com.pt.factory.method; import com.pt.factory.abstracted.MountainBike; import com.pt.factory.abstracted.RoadBikes; import java.io.*; import java.util.HashMap; import java.util.Map; /** * @description * @author panteng * @date 17-2-3. */ public class GiantBike extends AbstractBike implements MountainBike, RoadBikes, Cloneable, Serializable { /** 自行车种类:山地车 or 公路车 */ private String type = ""; /** 自行车ID */ private int id; /** 其他指标 */ private Map<String, Object> map = new HashMap<String, Object>(); /** * @description 展示外观 * @param * @return * @throws */ public void showAppearance(){ System.out.println("我是捷安特自行车,Type=" + this.type); } /** * 使用Object默认的为浅拷贝 * @return * @throws CloneNotSupportedException */ public GiantBike clone() throws CloneNotSupportedException{ return (GiantBike) super.clone(); } /** * 深拷贝 - 采用串行化的方式 * @return * @throws Exception */ public GiantBike deepClone() throws Exception{ ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream oo = new ObjectOutputStream(bo); oo.writeObject(this); ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream oi = new ObjectInputStream(bi); return (GiantBike) oi.readObject(); } public String getType(){ return type; } public void setType(String type){ this.type = type; } public int getId(){ return id; } public void setId(int id){ this.id = id; } public Map<String, Object> getMap(){ return map; } public void setMap(Map<String, Object> map){ this.map = map; } }
@Test public void testAssignment(){ GiantBike bike1 = new GiantBike(); bike1.setId(1); bike1.setType("giant1"); GiantBike bike2 = new GiantBike(); bike2.setType("giant2"); bike2.setId(2); System.out.println(bike1 == bike2); //false //赋值既不属于深拷贝 也不属于浅拷贝 bike2 = bike1; System.out.println(bike1 == bike2); //true bike2.setType("giant2"); bike2.setId(2); //此处赋值会影响bike1的值 System.out.println(bike1.getId()); } @Test public void copyTest() throws Exception{ GiantBike bike1 = new GiantBike(); bike1.setId(1); bike1.setType("giant1"); bike1.getMap().put("length", 90); //测试浅拷贝 GiantBike bike2 = bike1.clone(); System.out.println(bike2.getId() + " - " + bike2.getType() + " - " + bike2.getMap().get("length")); bike2.setId(2); bike2.setType("giant2"); bike2.getMap().put("length", 92);//在此处获取的map 与 bike1的map是同一个map,说明是浅拷贝 System.out.println(bike1.getId() + " - " + bike1.getType() + " - " + bike1.getMap().get("length")); //测试深拷贝 GiantBike bike3 = bike1.deepClone(); System.out.println(bike3.getId() + " - " + bike3.getType() + " - " + bike3.getMap().get("length")); bike3.setId(3); bike3.setType("giant3"); bike3.getMap().put("length", 93);//在此处获取的map 与 bike1的map不是同一个map,说明是深拷贝 System.out.println(bike1.getId() + " - " + bike1.getType() + " - " + bike1.getMap().get("length")); }
原型模型比较简单,核心类是一个包含复制方法的类,需要实现cloneable接口,其他类继承此类,即可实现克隆!
/* * Copyright (c) 2017. Xiaomi.Co.Ltd All rights reserved */ package com.pt.prototype; import java.io.*; /** * @description * @author panteng * @date 17-2-6. */ public class PrototypeModle implements Cloneable, Serializable { /** * 使用Object默认的为浅拷贝 * @return * @throws CloneNotSupportedException */ public PrototypeModle clone() throws CloneNotSupportedException{ return (PrototypeModle) super.clone(); } /** * 深拷贝 - 采用串行化的方式 * @return * @throws Exception */ public PrototypeModle deepClone() throws Exception{ ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream oo = new ObjectOutputStream(bo); oo.writeObject(this); ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream oi = new ObjectInputStream(bi); return (PrototypeModle) oi.readObject(); } }
@Test public void copyTest() throws Exception{ Cells cell1 = new Cells(); cell1.setId(1); cell1.setName("giant1"); cell1.getMap().put("length", 90); //测试浅拷贝 Cells cell2 = (Cells) cell1.clone(); System.out.println(cell2.getId() + " - " + cell2.getName() + " - " + cell2.getMap().get("length")); cell2.setId(2); cell2.setName("giant2"); cell2.getMap().put("length", 92);//在此处获取的map 与 cell1的map是同一个map,说明是浅拷贝 System.out.println(cell1.getId() + " - " + cell1.getName() + " - " + cell1.getMap().get("length")); //测试深拷贝 Cells cell3 = (Cells) cell1.deepClone(); System.out.println(cell3.getId() + " - " + cell3.getName() + " - " + cell3.getMap().get("length")); cell3.setId(3); cell3.setName("giant3"); cell3.getMap().put("length", 93);//在此处获取的map 与 cell1的map不是同一个map,说明是深拷贝 System.out.println(cell1.getId() + " - " + cell1.getName() + " - " + cell1.getMap().get("length")); System.out.println(cell3.getId() + " - " + cell3.getName() + " - " + cell3.getMap().get("length")); }