diff --git a/src/main/java/top/fjy8018/designpattern/pattern/creational/prototype/clone/CMailAfter.java b/src/main/java/top/fjy8018/designpattern/pattern/creational/prototype/clone/CMailAfter.java new file mode 100644 index 0000000..43fdb6d --- /dev/null +++ b/src/main/java/top/fjy8018/designpattern/pattern/creational/prototype/clone/CMailAfter.java @@ -0,0 +1,64 @@ +package top.fjy8018.designpattern.pattern.creational.prototype.clone; + +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +import java.util.Date; + +/** + * 原型模式:使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象 + * 适用于初始化对象复杂的场景 + *
+ * 邮件——深克隆实现 + * + * @author F嘉阳 + * @date 2018-09-25 20:39 + */ +@Slf4j +@Getter +@Setter +public class CMailAfter implements Cloneable { + + private String name; + /** + * String类型本身是不可变,不需要重新实现深克隆 + */ + private Date date; + private String content; + + public CMailAfter() throws InterruptedException { + // 模拟调用构造器需要复杂过程 + Thread.sleep(100); + log.debug(this.getClass().getSimpleName() + "构造器调用"); + } + + /** + * 带上父类toString方法查看是否为同一个对象 + * + * @return + */ + @Override + public String toString() { + return "CMailAfter{" + + "name='" + name + '\'' + + ", date=" + date + + ", content='" + content + '\'' + + '}'; + } + + /** + * 调用克隆函数不需要调用构造器以此加快实例化速度 + * 通过调用每个属性的克隆方法实现深克隆 + * + * @return + * @throws CloneNotSupportedException + */ + @Override + public Object clone() throws CloneNotSupportedException { + CMailAfter mail = (CMailAfter) super.clone(); + // 单独对Date进行克隆 + mail.date = (Date) date.clone(); + return mail; + } +} diff --git a/src/main/java/top/fjy8018/designpattern/pattern/creational/prototype/clone/CMailBefore.java b/src/main/java/top/fjy8018/designpattern/pattern/creational/prototype/clone/CMailBefore.java new file mode 100644 index 0000000..a3afe3a --- /dev/null +++ b/src/main/java/top/fjy8018/designpattern/pattern/creational/prototype/clone/CMailBefore.java @@ -0,0 +1,58 @@ +package top.fjy8018.designpattern.pattern.creational.prototype.clone; + +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +import java.util.Date; + +/** + * 原型模式:使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象 + * 适用于初始化对象复杂的场景 + *
+ * 邮件 + * + * @author F嘉阳 + * @date 2018-09-25 20:39 + */ +@Slf4j +@Getter +@Setter +public class CMailBefore implements Cloneable { + + private String name; + private Date date; + private String content; + + public CMailBefore() throws InterruptedException { + // 模拟调用构造器需要复杂过程 + Thread.sleep(100); + log.debug(this.getClass().getSimpleName() + "构造器调用"); + } + + /** + * 带上父类toString方法查看是否为同一个对象 + * + * @return + */ + @Override + public String toString() { + return "CMailBefore{" + + "name='" + name + '\'' + + ", date=" + date + + ", content='" + content + '\'' + + '}'; + } + + /** + * 调用克隆函数不需要调用构造器以此加快实例化速度 + * 通过调用每个属性的克隆方法实现深克隆 + * + * @return + * @throws CloneNotSupportedException + */ + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } +} diff --git a/src/test/java/top/fjy8018/designpattern/pattern/creational/prototype/before/BMailTest.java b/src/test/java/top/fjy8018/designpattern/pattern/creational/prototype/before/BMailTest.java index e7a9c28..79c09ff 100644 --- a/src/test/java/top/fjy8018/designpattern/pattern/creational/prototype/before/BMailTest.java +++ b/src/test/java/top/fjy8018/designpattern/pattern/creational/prototype/before/BMailTest.java @@ -6,6 +6,10 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import top.fjy8018.designpattern.pattern.creational.prototype.after.AMail; import top.fjy8018.designpattern.pattern.creational.prototype.after.AMailUtil; +import top.fjy8018.designpattern.pattern.creational.prototype.clone.CMailAfter; +import top.fjy8018.designpattern.pattern.creational.prototype.clone.CMailBefore; + +import java.util.Date; @Slf4j class BMailTest { @@ -66,6 +70,73 @@ class BMailTest { } // 本意希望在发送完所有邮件后保存开始的正文 AMailUtil.saveOriginMail(mail); + } + + /** + * 由于String不可变性保证其稳定性,而Date没有单独进行属性克隆导致 + *
+ * output + * === + * CMailBefore构造器调用 + * 15d0c81b CMailBefore{name='原始', date=Thu Jan 01 08:00:00 CST 1970, content='原始正文'} + * 4b1c1ea0 CMailBefore{name='原始', date=Thu Jan 01 08:00:00 CST 1970, content='原始正文'} + * =============== + * 15d0c81b CMailBefore{name='更新', date=Sun Sep 09 09:46:39 CST 2001, content='原始正文'} + * 4b1c1ea0 CMailBefore{name='原始', date=Sun Sep 09 09:46:39 CST 2001, content='原始正文'} + * 耗时109ms + * === + * + * @throws Exception + */ + @Test + void cloneTestBefore() throws Exception { + CMailBefore mail1 = new CMailBefore(); + mail1.setName("原始"); + mail1.setContent("原始正文"); + mail1.setDate(new Date(0L)); + CMailBefore mail2 = (CMailBefore) mail1.clone(); + log.debug(Integer.toHexString(mail1.hashCode()) + " " + mail1); + log.debug(Integer.toHexString(mail2.hashCode()) + " " + mail2); + + // 改变属性值 + mail1.setName("更新"); + mail1.getDate().setTime(999999999999L); + // 注意,若使用mail1.setDate(new Date());方式赋值不会导致两者同时变更 + log.debug("==============="); + log.debug(Integer.toHexString(mail1.hashCode()) + " " + mail1); + log.debug(Integer.toHexString(mail2.hashCode()) + " " + mail2); } + + /** + * output + * === + * CMailAfter构造器调用 + * 15d0c81b CMailAfter{name='原始', date=Thu Jan 01 08:00:00 CST 1970, content='原始正文'} + * 4b1c1ea0 CMailAfter{name='原始', date=Thu Jan 01 08:00:00 CST 1970, content='原始正文'} + * =============== + * 15d0c81b CMailAfter{name='更新', date=Sun Sep 09 09:46:39 CST 2001, content='原始正文'} + * 4b1c1ea0 CMailAfter{name='原始', date=Thu Jan 01 08:00:00 CST 1970, content='原始正文'} + * 耗时110ms + * === + * + * @throws Exception + */ + @Test + void cloneTestAfter() throws Exception { + CMailAfter mail1 = new CMailAfter(); + mail1.setName("原始"); + mail1.setContent("原始正文"); + mail1.setDate(new Date(0L)); + CMailAfter mail2 = (CMailAfter) mail1.clone(); + log.debug(Integer.toHexString(mail1.hashCode()) + " " + mail1); + log.debug(Integer.toHexString(mail2.hashCode()) + " " + mail2); + + // 改变属性值 + mail1.setName("更新"); + mail1.getDate().setTime(999999999999L); + log.debug("==============="); + log.debug(Integer.toHexString(mail1.hashCode()) + " " + mail1); + log.debug(Integer.toHexString(mail2.hashCode()) + " " + mail2); + } } \ No newline at end of file