创建型——原型模式
程序员文章站
2022-06-13 15:25:06
...
创建型——原型模式
原型模式相对其他创建型的设计模式比较容易。其核心就是克隆方法。Object.clone()
定义
- 原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
特点
- 不需要知道任何创建细节,不调用构造函数。
适用场景
-
类初始化需要消耗较多的资源
-
new产生的一个对象需要非常繁琐的过程(数据准备,访问权限等)
-
构造函数比较复杂
-
循环体中生产大量对象
优点
- 性能上比new 一个对象高
- 简化创建过程
缺点
- 必须配备克隆方法。Object.clone()方法。
- 对克隆复杂对象或者对克隆出的对象进行复杂改造的时候,会有风险。
- 深拷贝,浅拷贝。
Code
业务场景
- 邮件的创建。一封邮件包括:主题,收件人,抄送人,地址,内容,发送日期。邮件构建复杂
- 循环发送邮件
业务分析与模型构建
-
邮件的创建比较复杂,且需要循环进行发送,那么我们需要保存一份模板,然后动态的进行更改邮件里面的内容,最后循环发送。
-
Mail类进行构造邮件对象
-
MailUtil进行邮件的发送和模板记录
代码示例
import java.util.Date;
/**
* 邮件对象
*/
public class Mail implements Cloneable{
// 邮件主题
private String topic;
// 收件人
private String addressee;
// 抄送人列表
private String ccList;
// 邮箱地址
private String emailAddress;
//邮件内容
private String content;
// 发送日期
private Date sendDate;
public Mail() {
// 此处假设构造方法及其复杂 ...
}
// ... 忽略getter setter
// 克隆方法
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
- MailUtil
/**
* 邮件工具类,工具类一般要声明成final的
*/
public final class MailUtil {
// 私有构造防止有外加new 对象的。
private MailUtil(){}
public static void sendMail(Mail mail){
System.out.println("发送邮件成功!" + mail.getTopic());
}
public static void recordMailTemplate(Mail mail){
System.out.println("mail模板信息:" + mail.getContent());
}
}
- TestMain测试
/**
* 测试
*/
public class TestMain {
public static void main(String[] args) throws CloneNotSupportedException {
Mail mail = new Mail();
mail.setContent("邮件模板内容");
for (int i = 0; i < 10; i++) {
Mail mailClone = (Mail) mail.clone();
mailClone.setTopic("邮件测试" + i);
mailClone.setAddressee(i + "");
mailClone.setCcList(i + "");
mailClone.setContent("邮件测试" + i);
MailUtil.sendMail(mailClone);
}
// 这个保存模板的逻辑正常应该放在初始化模板之后
// 在这里,为了刚方便演示原型模式,故意放在最后来保存邮件模板内容
// 这个记录这一步骤里面,还会记录“邮件模板内容”几个字,而不是最后的“邮件测试9”
MailUtil.recordMailTemplate(mail);
}
}
深克隆,浅克隆——知识拓展
- 深克隆:引用和对象的某些属性都进行了克隆。
- 浅克隆:只克隆了引用,但是克隆的引用影响不了原来的引用持有的对象(读不懂这句话就运行一下下面的程序)
代码测试用例
- Mail 重点关注clone()方法
package creational.prototype;
import java.util.Date;
/**
* 邮件对象
* @author zhongyuan.zhao
* @date 2020-05-24 22:54
*/
public class Mail implements Cloneable{
// 邮件主题
private String topic;
// 收件人
private String addressee;
// 抄送人列表
private String ccList;
// 邮箱地址
private String emailAddress;
//邮件内容
private String content;
// 发送日期
private Date sendDate;
public Mail() {
// 此处假设构造方法及其复杂 ...
}
// 克隆方法
@Override
protected Object clone() throws CloneNotSupportedException {
// 深克隆的写法,需要将指定的引用属性也进行克隆
Mail mail = (Mail) super.clone();
mail.sendDate = (Date) mail.sendDate.clone();
return mail;
}
public Date getSendDate() {
return sendDate;
}
public void setSendDate(Date sendDate) {
this.sendDate = sendDate;
}
public String getTopic() {
return topic;
}
public void setTopic(String topic) {
this.topic = topic;
}
public String getAddressee() {
return addressee;
}
public void setAddressee(String addressee) {
this.addressee = addressee;
}
public String getCcList() {
return ccList;
}
public void setCcList(String ccList) {
this.ccList = ccList;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
- CloneTestMain
package creational.prototype;
import java.util.Date;
/**
* 克隆的测试
* @author zhongyuan.zhao
* @date 2020-05-24 23:21
*/
public class CloneTestMain {
public static void main(String[] args) throws CloneNotSupportedException {
Mail mail = new Mail();
mail.setSendDate(new Date());
Mail mailClone = (Mail) mail.clone();
System.out.println("=======初始状态======");
System.out.println(mail.getSendDate());
System.out.println(mailClone.getSendDate());
System.out.println("=======改变克隆对象的时候,原对象属性不改变======");
// 改变克隆对象的时候,原对象属性不改变
mailClone.setSendDate(new Date(0L));
System.out.println(mail.getSendDate());
System.out.println(mailClone.getSendDate());
// System.out.println("=======浅克隆的时候:改变原本对象,克隆对象会有改变,=======");
// // 还原初始值
// mailClone.setSendDate(mail.getSendDate());
// // 改变原对象的时候,克隆对象会有改变
// mail.setSendDate(new Date(0L));
// System.out.println(mail.getSendDate());
// System.out.println(mailClone.getSendDate());
System.out.println("=======深克隆的时候:改变原本对象,克隆对象不会有改变,=======");
mail.setSendDate(new Date(1000000000000000000L));
System.out.println(mail.getSendDate());
System.out.println(mailClone.getSendDate());
}
}
源码阅读
实现了Cloneable接口的都重写了clone方法。有兴趣可以阅读一下。
上一篇: Jsp servlet验证码工具类分享
下一篇: 九条爆笑男女多娇雷语