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接口。

原文地址:https://www.cnblogs.com/xuekyo/p/2587730.html