定义
原型实例指定创建对象的种类,通过拷贝这些原型创建新的对象
不需要知道任何创建的细节,不需要用到构造函数
简化创建对象过程,假设有一个类new对象的是比较耗资源的,那么原型模式就比较提高效率了
核心是clone方法
如果抽象类实现Cloneable接口并重写clone方法,那么子类继承此抽象类就可以直接使用原型模式
原型模式可以破坏单例模式,所以单例模式类不要实现Cloneable接口
demo设计
发邮件,根据邮件实体类Email连续发10封邮件 ,但是不需要new10个对象
实体类
Mail邮件实体类,注意要实现Cloneable接口,重写Object的clone方法
@Data
public class Mail implements Cloneable {
private String name;
private String emailAddress;
private String content;
public Mail() {
System.out.println("Mail class construct");
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
发生邮件的工具类
public class MailUtil {
public static void sendMail(Mail mail) {
String outputContent = "向{0},邮件地址:{1},邮件内容:{2}发送邮件";
System.out.println(MessageFormat.format(outputContent, mail.getName(), mail.getEmailAddress(), mail.getContent()));
}
public static void saveOriginMailRecord(Mail mail) {
System.out.println("存储mail记录: " + mail);
}
}
测试方法
public static void main(String[] args) throws CloneNotSupportedException {
Mail mail = new Mail();
mail.setContent("初始化模板");
for (int i = 0; i < 10; i++) {
//通过clone创建类
Mail tempMail = (Mail) mail.clone();
tempMail.setName(i + "同学");
tempMail.setEmailAddress(i + "同学" + "@qq.com");
tempMail.setContent("恭喜" + i + "同学中奖");
MailUtil.sendMail(tempMail);
}
MailUtil.saveOriginMailRecord(mail);
}
会出现的问题及解决方案
问题 浅拷贝
假设有一个pig类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Pig implements Cloneable {
private String name;
private Date birthday;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
类里所用的属性有引用类型
public static void main(String[] args) throws CloneNotSupportedException {
Date birthday = new Date(0L);
Pig pig1 = new Pig("1", birthday);
Pig pig2 = (Pig) pig1.clone();
System.out.println(pig1);
System.out.println(pig2);
//引用的是同一个对象
pig1.getBirthday().setTime(6666666666L);
System.out.println(pig1);
System.out.println(pig2);
}
查看运行信息,会发现pig1对象的属性更改后,pig2的属性也更改了
clone出来的对象的引用类型的属性指向的是同一个对象
解决方案 完成深拷贝
在实体类中把每一个引用类型也进行clone
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Pig implements Cloneable {
private String name;
private Date birthday;
@Override
protected Object clone() throws CloneNotSupportedException {
Pig pig = (Pig) super.clone();
//对每个引用对象单独clone才能实现深克隆 引用的就不是同一个对象了
pig.birthday = (Date) pig.birthday.clone();
return pig;
}
}