Prototype Pattern

本文详细介绍了Java中的Prototype模式,包括其定义、应用场景、实现方法,以及深拷贝和浅拷贝的区别。并通过具体示例展示了如何在Java中实现这两种拷贝。
1、定义

在软件开发中,有时候可能会需要创建一些特别复杂的对象,如果系统中已经存在同样类型的对象,并且不同的属性个数相差不大的话,用Prototype模式可能是一个理想的选择。

定义 :用原型实例指定创建物件的种类,并且通过拷贝这些原型创建新的物件。

Prototype 模式允许一个物件再创建另外一个可定制的物件,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型物件传给那个要发动创建的物件,这个要发动创建的物件通过请求原型物件拷贝它们自己来实施创建。

 

使用方法很简单,只要调用对象的clone方法返回一个新的对象就可以了。但是为什么没有其他新的方法来实现这个模式呢?因为Java中的Object提供了clone()方法来实现对象的克隆,所以Prototype模式实现一下子变得很简单.

在这个clone方法中,我们只要调用Object的克隆方法返回一个对象,就可以以最简单的方式实现Prototype模式。

在其他编程语言中,就需要创建一个当前类的新的对象,然后把当前对象本身的各属性的值复制一份给新创建的对象,并且返回新对象即可。

什么时候应该使用prototype模式呢? 
1.当你要创建的对象与现有运行时对象相似度很大时
2.为了避免创建类的工厂类导致层次复杂度增加时
3.当类的实例只有不多的几种状态时(此时需要引进原型管理器)

Prototype模式常用在一些对象管理器中。这些对象管理器本身一般为单例模式,主要负责对象的创建和返回。由于返回的对象的类型基本上是一致的,而且返回的对象的各项属性大多保持一致,只有极少数属性才需要修改,所以用Prototype无疑是极好的选择。

2、深拷贝和浅拷贝(调用父类的clone即可实现浅拷贝,注意返回类型为object,如果需要深度拷贝,则需要流化合反流化

需要注意的是:浅拷贝和深拷贝的区别。

简单的讲,浅拷贝就是只对当前对象的直属属性进行复制,如果其属性是基本类型的话,就复制原对象的值;如果其属性是其他对象的话,就复制对象的地址。而深拷贝则是麻烦的多,如果其属性是对象的话,就需要创建一个新的子属性的对象,并且对这个对象的各项属性进行复制,如果子属性还有子属性的话,则需要递归的进行复制操作

一切就看需求,如果那些属性的值不会被变更的话,那么只需要实现浅拷贝即可;否则,深拷贝就是必须的

java里的clone分为: 
A:浅复制(浅克隆): 浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。 
b:深复制(深克隆):深复制把要复制的对象所引用的对象都复制了一遍。 
Java中对象的克隆,为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。必须要遵循下面三点 
1.在派生类中覆盖基类的clone()方法,并声明为public【Object类中的clone()方法为protected的】。 
2.在派生类的clone()方法中,调用super.clone()。 
3.在派生类中实现Cloneable接口。 

[java]   view plain copy print ?
  1.  * @see  java.lang.Cloneable  
  2.  */  
  3. protected native <span style="color:#ff0000;">Object </span>clone() throws CloneNotSupportedException;  
  4.   
  5. /**  

Object类里的clone方法是浅复制(浅克隆)

利用序列化来做深复制,把对象写到流里的过程是序列化(Serilization)过程,而把对象从流中读出来的过程则叫做反序列化(Deserialization)过程。应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。,利用这个特性,可以做深拷贝 

利用流进行深拷贝,例:

//集合深拷贝

[java]   view plain copy print ?
  1. public Object clone(){    
  2.     
  3.         try <span style="color:#ff0000;">{//流化    
  4. </span>    
  5.             ByteArrayOutputStream ot = new ByteArrayOutputStream();    
  6.     
  7.             ObjectOutputStream oo = new ObjectOutputStream(ot);    
  8.     
  9.             oo.writeObject(this);    
  10.             <span style="color:#ff0000;">//反流化    
  11. </span>            ByteArrayInputStream it = new ByteArrayInputStream(ot.toByteArray());    
  12.     
  13.             ObjectInputStream oi = new ObjectInputStream(it);    
  14.     
  15.             return (oi.readObject());    
  16.     
  17.         } catch (IOException e) {    
  18.             e.printStackTrace();    
  19.             return null;    
  20.         } catch (ClassNotFoundException e) {    
  21.             e.printStackTrace();    
  22.             return null;    
  23.         }    
  24.     
  25.     }    

3、个人测试举例

 

浅拷贝:

[java]   view plain copy print ?
  1. package prototype;  
  2.   
  3.   
  4. /** 
  5.  * 原型模式 
  6.  * @author hanrk-2734 
  7.  * 
  8.  */  
  9. public class MyClone implements Cloneable {  
  10.       
  11.     private String  a="myclone";  
  12.       
  13.     private Student student=new Student();  
  14.       
  15.     //访问域是否必须改为public 最好改为public  
  16.     protected Object clone() throws CloneNotSupportedException {  
  17.         // TODO Auto-generated method stub  
  18.         return super.clone();  
  19.     }  
  20.   
  21.     public String getA() {  
  22.         return a;  
  23.     }  
  24.   
  25.     public void setA(String a) {  
  26.         this.a = a;  
  27.     }  
  28.   
  29.     public Student getStudent() {  
  30.         return student;  
  31.     }  
  32.   
  33.     public void setStudent(Student student) {  
  34.         this.student = student;  
  35.     }  
  36.   
  37.       
  38.       
  39. }  


 

[java]   view plain copy print ?
  1. package prototype;  
  2.   
  3. public class Student {  
  4.       
  5.     private String name="kerry";  
  6.   
  7.     public String getName() {  
  8.         return name;  
  9.     }  
  10.   
  11.     public void setName(String name) {  
  12.         this.name = name;  
  13.     }  
  14.   
  15. }  


 

[java]   view plain copy print ?
  1. package prototype;  
  2. /** 
  3.  * 测试克隆 
  4.  * @author hanrk-2734 
  5.  * 
  6.  */  
  7. public class TestClone {  
  8.       
  9.       
  10.     public static void main(String[] args) throws CloneNotSupportedException {  
  11.           
  12.         MyClone myClone=new MyClone();  
  13.         System.out.println("myclone:"+myClone.getA());  
  14.         MyClone myClone2=(MyClone) myClone.clone();  
  15.         System.out.println("myclone2:"+myClone2.getA());  
  16.         /** 
  17.          * 浅拷贝输出结果,对象(非基本数据类型)为内存地址,相等表示同一个对象,对象未被复制 
  18.          * myclone:myclone 
  19.                      myclone2:myclone 
  20.                      student:prototype.Student@de6ced 
  21.                      student:prototype.Student@de6ced 
  22.          */  
  23.         System.out.println("student:"+myClone.getStudent());  
  24.         System.out.println("student:"+myClone2.getStudent());  
  25.           
  26.     }  
  27. }  


深拷贝

 

[java]   view plain copy print ?
  1. package prototype;  
  2.   
  3. import java.io.ByteArrayInputStream;  
  4. import java.io.ByteArrayOutputStream;  
  5. import java.io.IOException;  
  6. import java.io.ObjectInputStream;  
  7. import java.io.ObjectOutputStream;  
  8. import java.io.Serializable;  
  9.   
  10.   
  11. /** 
  12.  * 原型模式 
  13.  * @author hanrk-2734 
  14.  * 
  15.  */  
  16. public class MyClone implements Cloneable ,Serializable{  
  17.       
  18.     private String  a="myclone";  
  19.       
  20.     private Student student=new Student();  
  21.       
  22.     //访问域是否必须改为public 最好改为public  
  23.     protected Object clone() throws CloneNotSupportedException {  
  24.         // TODO Auto-generated method stub  
  25. //      return super.clone();  
  26.         //深度拷贝:第一 复写克隆逻辑,改为流化和反流化;第二:非基本类型对象必须实现接口Serializable;第三类本身实现Serializable  
  27.             Object resultObject=null;  
  28.             ByteArrayOutputStream ot = new ByteArrayOutputStream();    
  29.     
  30.             ObjectOutputStream oo = null;  
  31.             try {  
  32.                 oo = new ObjectOutputStream(ot);  
  33.             } catch (IOException e2) {  
  34.                 // TODO Auto-generated catch block  
  35.                 e2.printStackTrace();  
  36.             }    
  37.     
  38.             try {  
  39.                 oo.writeObject(this);  
  40.             } catch (IOException e) {  
  41.                 // TODO Auto-generated catch block  
  42.                 e.printStackTrace();  
  43.             }    
  44.     
  45.             ByteArrayInputStream it = new ByteArrayInputStream(ot.toByteArray());    
  46.     
  47.             ObjectInputStream oi = null;  
  48.             try {  
  49.                 oi = new ObjectInputStream(it);  
  50.             } catch (IOException e1) {  
  51.                 // TODO Auto-generated catch block  
  52.                 e1.printStackTrace();  
  53.             }    
  54.     
  55.             try {  
  56.                 return resultObject=oi.readObject();  
  57.             } catch (IOException e) {  
  58.                 // TODO Auto-generated catch block  
  59.                 e.printStackTrace();  
  60.             } catch (ClassNotFoundException e) {  
  61.                 // TODO Auto-generated catch block  
  62.                 e.printStackTrace();  
  63.             }    
  64.         
  65.              return resultObject;  
  66.     }  
  67.   
  68.     public String getA() {  
  69.         return a;  
  70.     }  
  71.   
  72.     public void setA(String a) {  
  73.         this.a = a;  
  74.     }  
  75.   
  76.     public Student getStudent() {  
  77.         return student;  
  78.     }  
  79.   
  80.     public void setStudent(Student student) {  
  81.         this.student = student;  
  82.     }  
  83.   
  84.       
  85.       
  86. }  


[java]   view plain copy print ?
  1. package prototype;  
  2.   
  3. import java.io.Serializable;  
  4.   
  5. public class Student implements Serializable {  
  6.       
  7.     private String name="kerry";  
  8.   
  9.     public String getName() {  
  10.         return name;  
  11.     }  
  12.   
  13.     public void setName(String name) {  
  14.         this.name = name;  
  15.     }  
  16.   
  17. }  


[java]   view plain copy print ?
  1. package prototype;  
  2. /** 
  3.  * 测试克隆 
  4.  * @author hanrk-2734 
  5.  * 
  6.  */  
  7. public class TestClone {  
  8.       
  9.       
  10.     public static void main(String[] args) throws CloneNotSupportedException {  
  11.           
  12.         MyClone myClone=new MyClone();  
  13.         System.out.println("myclone:"+myClone.getA());  
  14.         MyClone myClone2=(MyClone) myClone.clone();  
  15.         System.out.println("myclone2:"+myClone2.getA());  
  16.         /** 
  17.          * 浅拷贝输出结果,对象(非基本数据类型)为内存地址 
  18.          * myclone:myclone 
  19.                     myclone2:myclone 
  20.            student:prototype.Student@de6ced 
  21.            student:prototype.Student@de6ced 
  22.          */  
  23.         /** 
  24.          * 深拷贝结果,student内存地址不同,对象被成功复制 
  25.          * myclone:myclone 
  26.            myclone2:myclone 
  27.            student:prototype.Student@89ae9e 
  28.             student:prototype.Student@1d58aae 
  29.  
  30.          */  
  31.         System.out.println("student:"+myClone.getStudent());  
  32.         System.out.println("student:"+myClone2.getStudent());  
  33.           
  34.     }  
  35. }  

转载于:https://my.oschina.net/hanruikai/blog/158071

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值