再战设计模式之原型模式
Posted bj-xiaodao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了再战设计模式之原型模式相关的知识,希望对你有一定的参考价值。
原型模式(prototype)
这个模式一般在工作中很少用,但是在框架里可能经常有,它是在什么情况下用呢?比如我们创建一个对象,需要10ms,在创建一个对象也需要10ms,这样就很耗时..
举一个很简单的例子.小A在考试,做一份卷子需要一个小时.这时候小A做完啦.小B把小A的卷子.copy过来用了几分钟.做了一些修改,可能比小A的分数还要高.这个就是原型模式
所以我们在创建对象的时候比较耗时.我们在创建一个的时候就可以用原型模式.
- 浅克隆
只负责克隆按值传递的数据(比如基本数据类型、String类型),而不复制它所引用的对象,换言之,所有的对其他对象的引用都仍然指向原来的对象。
- 深克隆
除了浅度克隆要克隆的值外,还负责克隆引用类型的数据。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深度克隆把要复制的对象所引用的对象都复制了一遍,而这种对被引用到的对象的复制叫做间接复制。
深度克隆要深入到多少层,是一个不易确定的问题。在决定以深度克隆的方式复制一个对象的时候,必须决定对间接复制的对象时采取浅度克隆还是继续采用深度克隆。因此,在采取深度克隆时,需要决定多深才算深。此外,在深度克隆的过程中,很可能会出现循环引用的问题,必须小心处理。
浅克隆
public class Sheep implements Cloneable{ //1997 年克隆羊 多利 private String name; private String[] color; public String getName() { return name; } public void setName(String name) { this.name = name; } public String[] getColor() { return color; } public void setColor(String[] color) { this.color = color; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
public class Client1 {
private static Unsafe unsafe;
static final boolean is64bit = true;
static {
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
unsafe = (Unsafe) field.get(null);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取对象的内存地址
* @param label
* @param objects
*/
public static void printAddresses(String label, Object... objects) {
System.out.print(label + ": 0x");
long last = 0;
int offset = unsafe.arrayBaseOffset(objects.getClass());
int scale = unsafe.arrayIndexScale(objects.getClass());
switch (scale) {
case 4:
long factor = is64bit ? 8 : 1;
final long i1 = (unsafe.getInt(objects, offset) & 0xFFFFFFFFL) * factor;
System.out.print(Long.toHexString(i1));
last = i1;
for (int i = 1; i < objects.length; i++) {
final long i2 = (unsafe.getInt(objects, offset + i * 4) & 0xFFFFFFFFL) * factor;
if (i2 > last)
System.out.print(", +" + Long.toHexString(i2 - last));
else
System.out.print(", -" + Long.toHexString( last - i2));
last = i2;
}
break;
case 8:
throw new AssertionError("Not supported");
}
System.out.println();
}
public static void main(String[] args) throws CloneNotSupportedException {
Sheep sheep1 = new Sheep();
String[] color = {"黑","白"};
sheep1.setName("多利");
sheep1.setColor(color);
System.out.println("原来 name= "+ sheep1.getName() +" 颜色: " + Arrays.toString( sheep1.getColor()));
Sheep sheep2 = (Sheep) sheep1.clone();
sheep2.setName("克隆??");
String[] color2 = {"黑11","白11"};
sheep2.setColor(color2);
System.out.println("克隆: name= " + sheep2.getName()+" 颜色 = " +Arrays.toString( sheep2.getColor()));
System.out.println(sheep1);
System.out.println(sheep2);
;
//这里看到前克隆之后.内存地址还是和原来指向一个内存地址
printAddresses("color",sheep2.getColor());
printAddresses("color",sheep1.getColor());
}
}
原来 name= 多利 颜色: [黑, 白]
克隆: name= 克隆?? 颜色 = [黑, 白]
结果 引用类型并没有还是原来对象的内存地址,并没有变成新的.
深克隆
public class Sheep implements Cloneable{ //1997 年克隆羊 多利 private String name; private String[] color; public String getName() { return name; } public void setName(String name) { this.name = name; } public String[] getColor() { return color; } public void setColor(String[] color) { this.color = color; } @Override protected Object clone() throws CloneNotSupportedException { Object object = super.clone(); this.color.clone(); return object; } } public class Client1 { private static Unsafe unsafe; static final boolean is64bit = true; static { try { Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); unsafe = (Unsafe) field.get(null); } catch (Exception e) { e.printStackTrace(); } } /** * 获取对象的内存地址 * @param label * @param objects */ public static void printAddresses(String label, Object... objects) { System.out.print(label + ": 0x"); long last = 0; int offset = unsafe.arrayBaseOffset(objects.getClass()); int scale = unsafe.arrayIndexScale(objects.getClass()); switch (scale) { case 4: long factor = is64bit ? 8 : 1; final long i1 = (unsafe.getInt(objects, offset) & 0xFFFFFFFFL) * factor; System.out.print(Long.toHexString(i1)); last = i1; for (int i = 1; i < objects.length; i++) { final long i2 = (unsafe.getInt(objects, offset + i * 4) & 0xFFFFFFFFL) * factor; if (i2 > last) System.out.print(", +" + Long.toHexString(i2 - last)); else System.out.print(", -" + Long.toHexString( last - i2)); last = i2; } break; case 8: throw new AssertionError("Not supported"); } System.out.println(); } public static void main(String[] args) throws CloneNotSupportedException { Sheep sheep1 = new Sheep(); String[] color = {"黑","白"}; sheep1.setName("多利"); sheep1.setColor(color); System.out.println("原来 name= "+ sheep1.getName() +" 颜色: " + Arrays.toString( sheep1.getColor())); Sheep sheep2 = (Sheep) sheep1.clone(); sheep2.setName("克隆??"); String[] color2 = {"黑11","白11"}; sheep2.setColor(color2); System.out.println("克隆: name= " + sheep2.getName()+" 颜色 = " +Arrays.toString( sheep2.getColor())); System.out.println(sheep1); System.out.println(sheep2); ; //这里看到前克隆之后.内存地址还是和原来指向一个内存地址 printAddresses("color",sheep2.getColor()); printAddresses("color",sheep1.getColor()); } } 原来 name= 多利 颜色: [黑, 白] 克隆: name= 克隆?? 颜色 = [黑11, 白11] [email protected] [email protected] color: 0x76ac297b0, +30 color: 0x76ac28f40, +30
大家看这里的color内存地址也变成新的地址了. 我们可以正常的修改克隆对象的引用了.
利用序列化和反序列实现深克隆
public class Sheep implements Cloneable , Serializable { //1997 年克隆羊 多利 private String name; private String[] color; public String getName() { return name; } public void setName(String name) { this.name = name; } public String[] getColor() { return color; } public void setColor(String[] color) { this.color = color; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } public class Client3 { public static void main(String[] args) throws IOException, ClassNotFoundException { Sheep sheep1 = new Sheep(); String[] color = {"黑","白"}; sheep1.setName("多利"); sheep1.setColor(color); //序列化和反序列 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream ots = new ObjectOutputStream(bos); ots.writeObject(sheep1); //sheep1 里面的数据. byte[] bytes = bos.toByteArray(); //反序列化 ByteArrayInputStream bis = new ByteArrayInputStream(bytes); ObjectInputStream ois = new ObjectInputStream(bis); Sheep sheepClone = (Sheep) ois.readObject(); String[] color1 = {"黑1","白22"}; sheepClone.setColor(color1); System.out.println("原来 name= "+ sheep1.getName() +" 颜色: " + Arrays.toString( sheep1.getColor())); System.out.println("克隆: name= " + sheepClone.getName()+" 颜色 = " + Arrays.toString( sheepClone.getColor())); } }
这里我就不获取内存地址了.我们通过修改克隆的对象的应用发现可以修改..就可以了.
以上是关于再战设计模式之原型模式的主要内容,如果未能解决你的问题,请参考以下文章