01.27 百年名校校長涉嫌學術造假?原型模式(Prototype Pattern)來解釋

目的

通過複製來降低創建複雜對象的時候耗時佔用的資源和降低耗時

例子代碼

鍋從天上來, 現任某開校長被指涉嫌抄襲, 論文換個圖就發了個新論文, 情況大概是這樣的:

我們簡化論文的結構如下:

<code>@Datapublic class Paper {    private String title;    private String introduction;    private Content content;    private String conclusion;}/<code>

其中正文類如下:

<code>@Datapublic class Content {    private String text;    private String picture;    @SneakyThrows    public Content(String text, String picture) {        this.text = text;        this.picture = picture;        //很耗時的操作        Thread.sleep(1000);    }}/<code>

我們用 Client 模擬遠程操作:

<code>public class Client {    //模擬遠程查詢操作    public static String queryTitle() {        return "氣功治癒癌症的研究";    }}/<code>

寫出二篇論文:

<code>        Paper firstPaper = new Paper();        firstPaper.setTitle(Client.queryTitle());        firstPaper.setIntroduction("青蛙是用腿叫的");        firstPaper.setContent(new Content("青蛙本來叫的好好的, " +                "切了腿就不叫了, 所以青蛙是用腿叫的",                "a.jpg"));        firstPaper.setConclusion("氣功對於治癒癌症確實有效果");        System.out.println("第一篇論文是 " + firstPaper);        //將圖片轉個 90 度變成新的論文        Paper secondPaper = new Paper();        secondPaper.setTitle(Client.queryTitle());        secondPaper.setIntroduction("青蛙是用腿叫的");        secondPaper.setContent(new Content("青蛙本來叫的好好的, " +                "切了腿就不叫了, 所以青蛙是用腿叫的",                "b.jpg"));        secondPaper.setConclusion("氣功對於治癒癌症確實有效果");        System.out.println("第二篇論文是 " + secondPaper);/<code>

問題分析

我們發現第一篇是沒辦法, 得寫, 第二篇不用一個個字的重新打, 思路也不用重新整理, 我們單純替換一下照片就是一個新的論文了, 省去了遠程調用的 IO 資源佔用和耗時

初步解決

我們為 paper 定義一個 clone 方法:

<code>@Datapublic class Paper implements Cloneable {    private String title;    private String introduction;    private Content content;    private String conclusion;    @Override    public Paper clone() {        Paper clonePaper = new Paper();        clonePaper.setTitle(this.title);        clonePaper.setIntroduction(this.introduction);        clonePaper.setContent(this.content);        clonePaper.setConclusion(this.conclusion);        return clonePaper;    }}/<code>

我們創建第二個代碼可以這麼寫:

<code>Paper firstPaper = new Paper();firstPaper.setTitle(Client.queryTitle());firstPaper.setIntroduction("青蛙是用腿叫的");firstPaper.setContent(new Content("青蛙本來叫的好好的, " +        "切了腿就不叫了, 所以青蛙是用腿叫的",        "a.jpg"));firstPaper.setConclusion("氣功對於治癒癌症確實有效果");System.out.println("第一篇論文是 " + firstPaper);Paper secondPaper = firstPaper.clone();secondPaper.getContent().setPicture("b.jpg");System.out.println("第一篇論文是 " + firstPaper);System.out.println("第二篇論文是 " + secondPaper);/<code>

看似沒什麼問題, 可是我們輸出的時候變成了這樣:

<code>第一篇論文是 Paper(title=氣功治癒癌症的研究, introduction=青蛙是用腿叫的, content=Content(text=青蛙本來叫的好好的, 切了腿就不叫了, 所以青蛙是用腿叫的, picture=a.jpg), conclusion=氣功對於治癒癌症確實有效果)第一篇論文是 Paper(title=氣功治癒癌症的研究, introduction=青蛙是用腿叫的, content=Content(text=青蛙本來叫的好好的, 切了腿就不叫了, 所以青蛙是用腿叫的, picture=b.jpg), conclusion=氣功對於治癒癌症確實有效果)第二篇論文是 Paper(title=氣功治癒癌症的研究, introduction=青蛙是用腿叫的, content=Content(text=青蛙本來叫的好好的, 切了腿就不叫了, 所以青蛙是用腿叫的, picture=b.jpg), conclusion=氣功對於治癒癌症確實有效果)/<code>

因為我們是淺複製, 我們複製後對象的屬性變了, 原來的對象的屬性也跟著變了, 這肯定不是我們希望的

原型模式

我們可以用序列化來實現深度複製:

<code>public class BeanUtil {    public static  T deepClone(T source, Class tClass) {        return GsonUtil.convert(GsonUtil.toJson(source), tClass);    }}/<code>

其中的 GsonUtil 如下:

<code>public class GsonUtil {    private static final Gson GSON = new GsonBuilder()            .enableComplexMapKeySerialization()            .create();    private GsonUtil() {    }    public static  T convert(String jsonStr, Class classOfT) {        return GSON.fromJson(jsonStr, classOfT);    }    public static String toJson(Object target) {        return GSON.toJson(target);    }}/<code>
百年名校校長涉嫌學術造假?原型模式(Prototype Pattern)來解釋

課後作業

  1. 使用深度複製完成 Paper 對象的複製
  2. 一個報銷單的一行如果由一個部門報銷就直接插入庫中, 由三個部門分攤報銷就需要複製報銷單的其他信息, 把原有的id後面加上1,2,3 這樣, 請用原型模式實現:
<code>@Data@EqualsAndHashCode(callSuper = false)@Accessors(chain = true)@TableName("m_c_expense_ReportEntry")public class MCExpenseReportEntry implements Serializable {    private static final long serialVersionUID = 1L;    @TableField("ExpenseTypeName")    private String expenseTypeName;    @TableField("CurrencyCode")    private String currencyCode;    @TableField("ApprovedAmount")    private BigDecimal approvedAmount;    @TableField("LocationCountry")    private String locationCountry;    @TableField("LocationName")    private String locationName;    @TableField("BusinessPurpose")    private String businessPurpose;    @TableField("JoinNum")    private String joinNum;    @TableField("AbnormalProblems")    private String abnormalProblems;    @TableField("ProblemsDescription")    private String problemsDescription;    @TableField("RecheckOpinion")    private String recheckOpinion;    @TableField("SecondInstance")    private String secondInstance;    @TableField("BearToPayDepartmentCode")    private String bearToPayDepartmentCode;    @TableField("BearToPayDepartment")    private String bearToPayDepartment;    @TableField("ReportID")    private String reportID;    @TableField("TransactionDate")    private LocalDateTime transactionDate;    @TableField("Report_Entry_Id")    private String reportEntryId;    private String isTax;    private String invoiceType;    @TableField("Percentage")    private String percentage;    @TableField("LastModifiedDate")    private String lastModifiedDate;    @TableField("financial_approval_date")    private LocalDateTime financialApprovalDate;}/<code>


分享到:


相關文章: