原型模式通用代码:
class PrototypeClass implements Cloneable { @Override protected PrototypeClass clone() throws CloneNotSupportedException { PrototypeClass prototypeClass = null; prototypeClass = (PrototypeClass) super.clone(); return prototypeClass; } }
实现Clonable接口,重写Clone方法,就完成了原型模式。
例子:
class AdvTemplate { // 广告信名称 private String advSubject = "XX银行国庆信用卡抽奖活动"; // 广告信内容 private String advContxt = "国庆抽奖活动通知:只要刷卡就送你一百万!"; public String getAdvSubject() { return this.advSubject; } public String getAdvContxt() { return advContxt; } } class Mail implements Cloneable { // 收件人 private String receiver; // 邮件名称 private String subject; // 称谓 private String appellation; // 邮件内容 private String contxt; // 邮件的尾部,一般都是加上“XX版权所有”等信息 private String tail; public Mail(AdvTemplate advTemplate) { this.contxt = advTemplate.getAdvContxt(); this.subject = advTemplate.getAdvSubject(); } 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; } @Override protected Mail clone() { Mail mail = null; try { mail = (Mail) super.clone(); } catch (Exception e) { e.printStackTrace(); } return mail; } } 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(); mail.setAppellation(getReadingString(5) + " 先生 (女士) "); mail.setReceiver(getReadingString(5) + "@" + getReadingString(8) + ".com"); // 发送邮件 sendMail(cloneMail); i++; } } private static void sendMail(Mail mail) { System.out.println("标题: " + mail.getSubject() + "\t 收件人 : " + mail.getReceiver() + "\t 发送成功! "); } // 获得指定长度的字符串 private static String getReadingString(int length) { String source = "qwertyuiopsdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"; StringBuffer sb = new StringBuffer(); Random random = new Random(); for (int i = 0; i < length; i++) { sb.append(source.charAt(random.nextInt(source.length()))); } return sb.toString(); } }
原型模式的优点:
性能优良
逃避构造函数的约束
原型模式的使用场景:
资源优化场景
性能和安全要求的场景
一个对象多个修改者的场景
原型模式注意事项:
1.构造函数不会执行
一个实现了Cloneable接口并重写了clone方法的类A,有一个无参构造或有参构造B,通过new关键字产生了一个对象S
再然后通过S.clone方式产生了一个对象T,那么在对象拷贝时构造函数B是不会被执行的。
2.浅拷贝和深拷贝
浅拷贝:
class Thing implements Cloneable { // 定义一个私有变量 private ArrayList<String> arrayList = new ArrayList<String>(); @Override protected Thing clone() throws CloneNotSupportedException { Thing thing = null; thing = (Thing) super.clone(); return thing; } public void setValue(String value) { this.arrayList.add(value); } public ArrayList<String> getValue() { return this.arrayList; } } public class client { public static void main(String[] args) throws CloneNotSupportedException { Thing thing = new Thing(); thing.setValue("张三"); Thing cloneThing = thing.clone(); cloneThing.setValue("李四"); System.out.println(thing.getValue()); } }
Object类提供的方法clone只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素地址,这种拷贝就叫做浅拷贝。
确实是非常浅,两个对象共享了一个私有变量,两个对象都可以对其进行改变,是一种非常不安全的方式。
但是对于String类型,Java就希望你把它认为是基本类型,它是没有clone方法的,处理机制也比较特殊,通过字符串池在需要的时候才在内存中
创建新的字符串。
使用原型模式时,引用的成员变量必须满足两个条件才不会被拷贝:一是类的成员变量,而不是方法内变量;二是必须是一个可变的引用对象,而不是一个
原始类型或不可便对象。
深拷贝:
class DeepThing implements Cloneable { private ArrayList<String> arrayList = new ArrayList<String>(); @Override protected DeepThing clone() throws CloneNotSupportedException { DeepThing thing = null; thing = (DeepThing) super.clone(); this.arrayList = (ArrayList<String>) this.arrayList.clone(); return thing; } public void setValue(String value) { this.arrayList.add(value); } public ArrayList<String> getValue() { return this.arrayList; } } public class deepClient { public static void main(String[] args) throws Exception { DeepThing thing = new DeepThing(); thing.setValue("张三"); DeepThing cloneThing = thing.clone(); cloneThing.setValue("李四"); System.out.println(thing.getValue()); } }
只是比之前的例子多了
this.arrayList = (ArrayList<String>) this.arrayList.clone();
该方法就实现了完全的拷贝,两个对象之间没有任何的瓜葛了,互不影响,这就是深拷贝。
深拷贝还有一种实现方式时通过 自己写二进制流来操作对象,然后实现对象的拷贝。
clone和final是有冲突的
将ArrayList定义为final,编译器就会报错。