设计模式之原型模式
原型模式:
定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
通俗来说就是,先创建一个原型类,然后在里面写一个实现Cloneable接口(这个是java自带的)的函数clone(这个函数中需要调用clone函数【因为在父类中clone函数是protected不能直接调用,所以要重写】,这个函数是Object对象自带的,所有的类都继承自Object)。然后在原型类的外面通过new实例一份初始对象,然后通过clone这一份初始的大量的复制很多个同样的对象,这些对象都是一模一样。
以群发电子邮件为例:
public class Mail implements Cloneable{ //收件人 private String receiver; //邮件名称 private String subject; //称谓 private String appellation; //邮件内容 private String contxt; //邮件的尾部,一般都是加上“XXX版权所有”等信息 private String tail; //构造函数 public Mail(AdvTemplate advTemplate){ this.contxt = advTemplate.getAdvContext(); this.subject = advTemplate.getAdvSubject(); } @Override public Mail clone(){ Mail mail =null; try { mail = (Mail)super.clone(); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return mail; } //以下为getter/setter方法 public String getReceiver() { return receiver; } public void setReceiver(String receiver) { this.receiver = receiver; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } public String getAppellation() { return appellation; } public void setAppellation(String appellation) { this.appellation = appellation; } public String getContxt() { return contxt; } public void setContxt(String contxt) { this.contxt = contxt; } public String getTail() { return tail; } public void setTail(String tail) { this.tail = tail; } }
注意看黑体部分,实现了一个接口,并重写了clone方法,大家可能看着这个类有点奇怪,先保留你的好奇,我们继续讲下去,稍后会给你清晰的解答。我们再来看场景Client的变化,如下所示。
public class Client { //发送账单的数量,这个值是从数据库中获得 private static int MAX_COUNT = 6; public static void main(String[] args) { //模拟发送邮件 int i=0; //把模板定义出来,这个是从数据中获得 Mail mail = new Mail(new AdvTemplate()); mail.setTail("XX银行版权所有"); while(i<MAX_COUNT){ //以下是每封邮件不同的地方 Mail cloneMail = mail.clone(); cloneMail.setAppellation(getRandString(5)+" 先生(女士)"); cloneMail.setReceiver(getRandString(5) + "@" + getRandString(8)+".com"); //然后发送邮件 sendMail(cloneMail); i++; } } }
为什么要使用clone而不使用new每个都创建对象的方法呢?
1.clone的原型方法不需要运行整个类的任何方法就可以得到原始数据及数据模型,因为它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。明显直接操控硬件地址要更快更轻松
2.改动部分小,只需要改变大家都不同的地方即可
这个就好比手动写信和用复印机复印的区别
注意深拷贝和浅拷贝
深拷贝:把引用的对象的变量指向复制过的新对象,而不是原有被引用的对象。
浅拷贝:被复制对象的所有变量都含有与原来的对象的相同的值,而所有的对其他对象的引用都仍指向原来的对象。
深拷贝主要是可以更深入的拷贝要拷贝对象的变化的部分(引用数据,如创建的对象等等)而浅拷贝不能,它只能拷贝基本的数据类型,不能拷贝引用数据类型
深拷贝的具体实现是在将变化的部分也在变化的内部创建一个clone函数,然后再要拷贝的类中调用它的clone
//深拷贝的实现
public class Prototype implements Cloneable { private ArrayList list = new ArrayList(); public Prototype clone(){ Prototype prototype = null; try{ prototype = (Prototype)super.clone(); prototype.list = (ArrayList) this.list.clone(); }catch(CloneNotSupportedException e){ e.printStackTrace(); } return prototype; } }
在一些特定的场合会涉及到深拷贝和浅拷贝,如:数据集dataset,有clone和copy方法,clone复制其结构,copy复制结构和数据
http://www.cnblogs.com/cbf4life/archive/2009/12/10/1621453.html
http://blog.csdn.net/zhengzhb/article/details/7393528