设计模式7-原型模式

时间:2022-09-09 09:10:51

    原型模式其实是利用对象克隆来实现的,相对而言比较简单,使用克隆可以节约大量的资源。下面使用银行发对账单的邮件的例子,类图如下:

设计模式7-原型模式


    类图中AdvTemplate是广告信的模板,一般都是从数据库取出;Mail类是一封邮件类。

   广告信模板代码如下:

package com.jack.prototype;

/**
* Created by jack on 2017/8/3.
* 广告信模板
*/
public class AdvTemplate {
//广告信名称
private String advSubject = "招商银行信用卡活动";
//广告信内容
private String advContext = "将举行国庆抽奖活动,消费满100,送10000000积分";

public String getAdvSubject() {
return advSubject;
}

public void setAdvSubject(String advSubject) {
this.advSubject = advSubject;
}

public String getAdvContext() {
return advContext;
}

public void setAdvContext(String advContext) {
this.advContext = advContext;
}
}


邮件类代码如下:

package com.jack.prototype;

/**
* Created by jack on 2017/8/3.
* 邮件类
*/
public class Mail implements Cloneable{
/**
* 收件人
*/
private String receiver;
/**
* 邮件名称
*/
private String subject;
/**
* 称谓
*/
private String appellation;
/**
* 邮件内容
*/
private String context;
/**
* 邮件尾部
*/
private String tail;

/**
* 构造函数
* @param advTemplate
*/
public Mail(AdvTemplate advTemplate){
this.context = advTemplate.getAdvContext();
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 getContext() {
return context;
}

public void setContext(String context) {
this.context = context;
}

public String getTail() {
return tail;
}

public void setTail(String tail) {
this.tail = tail;
}

@Override
protected Mail clone() throws CloneNotSupportedException {
Mail mail = null;
try {
mail = (Mail) super.clone();
}catch (Exception e){
e.printStackTrace();
}

return mail;
}
}


测试邮件发送的代码如下:

package com.jack.prototype;

import java.util.Random;

/**
* Created by jack on 2017/8/3.
*/
public class MainTest4 {
public static void main(String[] args) throws CloneNotSupportedException {
int maxCount = 8;
int i = 0;
//把模板定义出来
Mail mail = new Mail(new AdvTemplate());
mail.setTail("招商银行版权所有");
while (i < maxCount) {
//使用克隆,原型模式
Mail cloneMail = mail.clone();
//下面时每个邮件不同的地方
cloneMail.setAppellation(getRandString(5)+"先生(女生)");
cloneMail.setReceiver(getRandString(5)+"@"+getRandString(8));
//发送邮件
sendMail(cloneMail);
i++;
}
}

/**
* 发送邮件
* @param mail
*/
public static void sendMail(Mail mail){
System.out.println("标题:"+mail.getSubject()+"\t收件人:"+mail.getReceiver()+"\t....发送成功!!!");
}

/**
* 获得指定长度的随机字符串
* @param maxLength
* @return
*/
public static String getRandString(int maxLength){
String source = "abcdefghijklmnopqrstuvwxyz";
StringBuffer sb = new StringBuffer();
Random random = new Random();
for (int i = 0 ;i < maxLength;i++){
sb.append(source.charAt(random.nextInt(source.length())));
}
return sb.toString();
}

}


   测试程序输入如下:

标题:招商银行信用卡活动	收件人:ytbyi@imyjuipe	....发送成功!!!
标题:招商银行信用卡活动 收件人:covuz@zogjxyji ....发送成功!!!
标题:招商银行信用卡活动 收件人:xauak@ehpvnkic ....发送成功!!!
标题:招商银行信用卡活动 收件人:vqere@enrhzmgk ....发送成功!!!
标题:招商银行信用卡活动 收件人:bepne@fxjheubf ....发送成功!!!
标题:招商银行信用卡活动 收件人:lihni@zlsjrspk ....发送成功!!!
标题:招商银行信用卡活动 收件人:pgzro@aipappjy ....发送成功!!!
标题:招商银行信用卡活动 收件人:frwcr@juhqjlql ....发送成功!!!


   上面使用了克隆技术,也就是原型模式,因为发送邮件一般是多线程的,进行发送邮件的过程中里面的信息可能随时改变,利用克隆技术可以拷贝对象的复制,改变不影响原对象。这种不通过new关键字产生一个对象,而是通过对象复制来实现的模式就叫做原型模式。原型模式的核心就是clone方法,该方法是Object类里面的方法,通过该方法进行对象的拷贝,通过Cloneable接口来表示这个对象是可拷贝的。在JVM中具有这个标记的对象才有可能被拷贝。那怎么才能从有可能拷贝转换为可以被拷贝呢?方法是覆盖clone方法。


    原型模式的优点:

1,性能优良,原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好的体现其优点。

2,逃避构造函数的约束,者既是优点又是缺点,直接在内存中拷贝,构造函数不会执行。优点就是减少了约束,缺点也就是减少了约束,需要大家在实际应用时考虑。

  

原型模式的使用场景:

1,*优化场景,类初始化需要消化非常多的资源

2,性能和安全要求的场景,通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式

3,一个对象多个修改者的场景,一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用