Prototype
原型模式定义:创建对象的种类,并且通过拷贝这些原型创建新的对象。
Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节。
工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。
原型模式好处:每次NEW一个对象,都需要执行一次构造函数,如果构造函数时间长,那么多次执行初始化的效率大大降低了。一般在初始化信息不变化的情况下,克隆是最好的方法。这既隐藏了对象创造的细节,又对性能是大大的提升。
1 //所有要克隆的类必须实现一个标识接口Cloneable,否则会抛出CloneNotSupportedException 2 public abstract class Prototype implements Cloneable { 3 4 protected String action = "nothing"; 5 6 public Prototype(){} 7 8 public Prototype(String action){ 9 this.action = action; 10 } 11 12 public Prototype cloneObj(){ 13 try { 14 return (Prototype) this.clone(); 15 } catch (CloneNotSupportedException e) { 16 System.err.println("Prototype is not Cloneable"); 17 } 18 return this; 19 } 20 21 public String getAction() { 22 return action; 23 } 24 25 public void setAction(String action) { 26 this.action = action; 27 } 28 29 }
1 public class ConcretePrototype extends Prototype { 2 3 private int flag = 1; 4 5 public ConcretePrototype(){} 6 7 public ConcretePrototype(String action){ 8 super(action); 9 } 10 11 public void sayHi(){ 12 System.out.println(flag + " : " + action); 13 } 14 15 }
1 public static void main(String[] args) { 2 3 ConcretePrototype cp = new ConcretePrototype("swing"); 4 ConcretePrototype cp1 = (ConcretePrototype) cp.cloneObj(); 5 6 System.out.println(cp==cp1); 7 cp1.setAction("run"); 8 9 cp.sayHi(); 10 cp1.sayHi(); 11 }
打印结果:
false
1 : swing
1 : run
浅复制:复制了值类型对象,对于引用类型对象,只复制了引用,它指向原来引用的对象。Java中clone为浅复制。
深复制:被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。
1 class Wing implements Cloneable, Serializable{ 2 3 private static final long serialVersionUID = 1L; 4 5 private int width; 6 7 private int weight; 8 9 public Wing(int width, int weight){ 10 this.width = width; 11 this.weight = weight; 12 } 13 14 public int getWidth() { 15 return width; 16 } 17 18 public void setWidth(int width) { 19 this.width = width; 20 } 21 22 public int getWeight() { 23 return weight; 24 } 25 26 public void setWeight(int weight) { 27 this.weight = weight; 28 } 29 30 public Wing clone(){ 31 try { 32 return (Wing)super.clone(); 33 } catch (CloneNotSupportedException e) { 34 System.out.println("can't clone !"); 35 } 36 return this; 37 } 38 39 }
1 public class Plane implements Cloneable, Serializable{ 2 3 private static final long serialVersionUID = 1L; 4 5 private Wing wing; 6 7 private String name; 8 9 public Plane(String name, Wing wing){ 10 this.name = name; 11 this.wing = wing; 12 } 13 14 public void sayHi(){ 15 System.out.println("plane : " + name + " , wing width : " + 16 wing.getWidth() + " , wing weight : " + wing.getWeight() + " ."); 17 } 18 19 /*浅复制 20 * public Plane clone(){ 21 try { 22 return (Plane)super.clone(); 23 } catch (CloneNotSupportedException e) { 24 System.out.println("can't clone !"); 25 } 26 return this; 27 }*/ 28 29 /*深复制 Plane Wing 都 implements Cloneable, 可以不继承 Serializable 30 * public Plane clone(){ 31 try { 32 Plane p = (Plane)super.clone(); 33 p.setWing(this.wing.clone()); 34 return p; 35 } catch (CloneNotSupportedException e) { 36 System.out.println("can't clone !"); 37 } 38 return this; 39 }*/ 40 41 /* 42 * 深复制 Plane Wing 都 implements Serializable, 可以不继承 Cloneable 43 */ 44 public Plane clone(){ 45 try { 46 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 47 ObjectOutputStream oos = new ObjectOutputStream(bos); 48 oos.writeObject(this); 49 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); 50 ObjectInputStream ois = new ObjectInputStream(bis); 51 return (Plane)ois.readObject(); 52 } catch (IOException e) { 53 System.out.println("io exception !"); 54 } catch (ClassNotFoundException e) { 55 System.out.println("can't clone !"); 56 } 57 return this; 58 } 59 60 public Wing getWing() { 61 return wing; 62 } 63 64 public void setWing(Wing wing) { 65 this.wing = wing; 66 } 67 68 public String getName() { 69 return name; 70 } 71 72 public void setName(String name) { 73 this.name = name; 74 } 75 76 }
1 public static void main(String[] args) { 2 Wing wing = new Wing(200,1000); 3 Plane p1 = new Plane("A", wing); 4 Plane p2 = p1.clone(); 5 wing.setWidth(500); 6 p1.sayHi(); 7 p2.sayHi(); 8 }
打印结果:
plane : A , wing width : 500 , wing weight : 1000 .
plane : A , wing width : 200 , wing weight : 1000 .
利用串行化来做深复制
把对象写到流里的过程是串行化(Serilization)过程,但是在Java程序师圈子里又非常形象地称为“冷冻”或者“腌咸菜(picking)”过程;而把对象从流中读出来的并行化(Deserialization)过程则叫做“解冻”或者“回鲜(depicking)”过程。应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面,因此“腌成咸菜”的只是对象的一个拷贝,Java咸菜还可以回鲜。
在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里(腌成咸菜),再从流里读出来(把咸菜回鲜),便可以重建对象。
(1)Java的clone()方法
1.clone方法将对象复制了一份并返回给调用者。一般而言,clone()方法满足:
2.对任何的对象x,都有x.clone() !=x//克隆对象与原对象不是同一个对象
3.对任何的对象x,都有x.clone().getClass()= =x.getClass()//克隆对象与原对象的类型一样
4.如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。
(2)Java中对象的克隆
1.为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。
2.在派生类中覆盖基类的clone()方法,并声明为public。
3.在派生类的clone()方法中,调用super.clone()。
4.在派生类中实现Cloneable接口。