原型模式的简单程度仅次于单例模式,核心方法就一个clone(),在java中只需要实现接口Cloneable即可
原型模式通过把对象复制(clone)一遍,产生一个新的对象,和原有对象一样,然后再修改细节...这样就可以不用new一个新的对象了
之所以这样做,肯定是有道理的,比如可以避免线程安全问题、节约时间等等
原型模式类图
index.png
这种形式涉及到三个角色
(1)客户(Client)角色:客户类提出创建对象的请求。
(2)抽象原型(Prototype)角色:这是一个抽象角色,通常由一个Java接口或Java抽象类实现。此角色给出所有的具体原型类所需的接口。
(3)具体原型(Concrete Prototype)角色:被复制的对象。此角色需要实现抽象的原型角色所要求的接口。
参考代码设计模式之蝉里的例子..
背景的银行给大量用户发广告信息,这个信息有些部分相同,有些部分不同,并且需要发送数量较大,所以用原型模式解决
广告模板代码
package test;
public class AdvTemplate {
private String advSubject = "XX银行国庆信用卡抽奖活动";
private String advContext = "国庆抽奖活动通知:只要刷卡就送你一百万!...";
public String getAdvSubject() {
return advSubject;
}
public String getAdvContext() {
return advContext;
}
}
邮件类代码
package test;
public class Mail implements Cloneable {
private String receiver;
private String subject;
private String appellation;
private String context;
private String tail;
public Mail(AdvTemplate advTemplate) {
this.context = advTemplate.getAdvContext();
this.subject = advTemplate.getAdvSubject();
}
@Override
protected Object clone() throws CloneNotSupportedException {
Mail mail = null;
try {
mail = (Mail)super.clone();
} catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return mail;
}
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 getContext() {
return context;
}
public void setContext(String context) {
this.context = context;
}
public String getTail() {
return tail;
}
public void setTail(String tail) {
this.tail = tail;
}
}
package test;
import java.util.ArrayList;
public class Thing implements Cloneable {
private ArrayList<String> arrayList = new ArrayList<String>();
@Override
protected Thing clone() throws CloneNotSupportedException {
Thing thing = null;
try {
thing = (Thing)super.clone();
this.arrayList = (ArrayList<String>)this.arrayList.clone();
} catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return thing;
}
public void setValue(String value) {
this.arrayList.add(value);
}
public ArrayList<String> getValue() {
return this.arrayList;
}
}
场景类代码
package test;
import java.util.Random;
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;
try {
cloneMail = (Mail)mail.clone();
cloneMail.setAppellation(getRandString(5) + " 先生(女生)");
cloneMail.setReceiver(getRandString(5) + "@" + getRandString(8) + ".com");
sendMail(cloneMail);
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
i ++;
}
Thing thing = new Thing();
thing.setValue("张三");
try {
Thing cloneThing = thing.clone();
cloneThing.setValue("李四");
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(thing.getValue());
}
public static void sendMail(Mail mail) {
System.out.println("标题:" + mail.getSubject() + "\t收件人:" + mail.getReceiver() + "\t...发送成功!");
}
public static String getRandString(int maxLength) {
String source = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
StringBuffer sb = new StringBuffer();
Random rand = new Random();
for(int i = 0; i < maxLength; i ++) {
sb.append(source.charAt(rand.nextInt(source.length())));
}
return sb.toString();
}
}
原型模式需要注意的就是深拷贝和浅拷贝的问题
在用java clone方法拷贝的时候,其对象内的数组和引用对象等都不拷贝,一个final类型的变量也不拷贝
比如对象中如果含有arrayList则不会拷贝
但加上thing.arrayList(ArrayList<String>)this.arrayList.clone();
就成了深拷贝,就能拷贝了
clone和final是两个冤家,相爱相杀吧,这俩是有冲突的要注意
网友评论