学习路径:https://coding.imooc.com/class/270.html
应用场景 需要同一个类的多个不同对象完成业务操作,群发email,需要多个Mail类的对象 好处:提高性能 public static void main(String[] args) throws CloneNotSupportedException { Mail mail = new Mail(); mail.setContent("初始化模板"); for(int i=0; i<10; i++) { //创建10个Mail的对象进行发邮件的操作,使用原型模式加快性能 Mail mailTemp = (Mail) mail.clone(); mailTemp.setName("第" + i + "个克隆出来的对象"); // 使用克隆采用的是二进制的拷贝,效率比直接new高很多 } // 不改变原来的Mail MailUtil.saveOriginMailRecord(mail); } 实现 // 省略get set方法 public class Mail implements Cloneable{ private String name; private String address; private String content; public Mail() { System.out.println("Mail Class Constructor"); } /** * 记得重写方法 * @return * @throws CloneNotSupportedException */ @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Mail{" + "name='" + name + '\'' + ", address='" + address + '\'' + ", content='" + content + '\'' + '}'; } } public class MailUtil { public static void sendMail(Mail mail) { String outputContent = "向{0}同学,邮件地址{1},邮件内容:{2},发送成功"; System.out.println(MessageFormat.format(outputContent, mail.getName(),mail.getAddress(),mail.getContent())); } public static void saveOriginMailRecord(Mail mail) { System.out.println("存储originMail记录,originMail:" + mail.getContent()); } } 原理原型模式的本质是类继承Clonable接口,重写clone方法。clone的底层是使用二进制拷贝,需要多个对象的时候可以用该方法取代多次new,提高性能。
坑 修改原对象的成员变量,可能会同时修改克隆出来的对象。避免这种坑即使用深拷贝。不重写clone方法,默认使用浅拷贝
public class Pig implements Cloneable{ private String name; // 引用对象 private Date birthday; // 默认的clone方法,不会修改引用对象的指向,即拷贝出来的对象中birthday引用指向的是同一块内存区域 @Override protected Object clone() throws CloneNotSupportedException { Pig pig = (Pig)super.clone(); // 深拷贝,有引用对象的时候需要重写clone()方法 pig.birthday = (Date)pig.birthday.clone(); return pig; } } 拓展 原型模式和单例模式结合的时候,注意修改clone方法1.极端场景
// step 2克隆破坏单例 HungrySingleton hungrySingleton = HungrySingleton.getInstance(); Method method = hungrySingleton.getClass().getDeclaredMethod("clone"); method.setAccessible(true); HungrySingleton cloneHungrySingleton = (HungrySingleton) method.invoke(hungrySingleton); System.out.println(hungrySingleton); System.out.println(cloneHungrySingleton);2.关键代码
/** * 单例模式下使用的clone方法, 防止克隆破坏就要修改方法实现 * @return * @throws CloneNotSupportedException */ @Override protected Object clone() throws CloneNotSupportedException { return getInstance(); }