定义
原型实例指定创建对象的种类,通过拷贝这些原型创建新的对象
不需要知道任何创建的细节,不需要用到构造函数
简化创建对象过程,假设有一个类new对象的是比较耗资源的,那么原型模式就比较提高效率了
核心是clone方法
如果抽象类实现Cloneable接口并重写clone方法,那么子类继承此抽象类就可以直接使用原型模式
原型模式可以破坏单例模式,所以单例模式类不要实现Cloneable接口
demo设计
发邮件,根据邮件实体类Email连续发10封邮件 ,但是不需要new10个对象
实体类
Mail邮件实体类,注意要实现Cloneable接口,重写Object的clone方法
@Datapublic class Mail implements Cloneable {private String name;private String emailAddress;private String content;public Mail() {System.out.println("Mail class construct");}@Overrideprotected 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@AllArgsConstructorpublic class Pig implements Cloneable {private String name;private Date birthday;@Overrideprotected 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@AllArgsConstructorpublic class Pig implements Cloneable {private String name;private Date birthday;@Overrideprotected Object clone() throws CloneNotSupportedException {Pig pig = (Pig) super.clone();//对每个引用对象单独clone才能实现深克隆 引用的就不是同一个对象了pig.birthday = (Date) pig.birthday.clone();return pig;}}
