Java 23種設計模式 之 原型模式

2020-09-28 12:01:43

原型模式,以一個物件為原型進行復制(克隆)的設計模式,故引申出來深克隆與淺克隆知識。

原型模式解決的問題

舉個例子:比如我們要抄襲某位博主的部落格,部落格包括 標題,正文,文末的引流連結
我們有兩個類

原型 - Blog類

public class Blog {

    String title = "被抄襲的部落格標題";
    String text = "被抄襲的部落格正文";
    ReferenceLink referenceLink = new ReferenceLink();//文末的引流連結

    public Blog() {
    }

    public Blog(String title, String text, ReferenceLink referenceLink) {
        this.title = title;
        this.text = text;
        this.referenceLink = referenceLink;
    }

    public String getTitle() {
        return title;
    }

    public String getText() {
        return text;
    }

    public ReferenceLink getReferenceLink() {
        return referenceLink;
    }
}
@Override
    public String toString() {
        return "Blog{" +
                "title='" + title + '\'' +
                ", text='" + text + '\'' +
                ", referenceLink=" + referenceLink.QQ + referenceLink.str +
                '}';
    }

引流連結類

public class ReferenceLink {

   String QQ = "qq466009264";
    String str = "來騷擾我呀";

    public String getQQ() {
        return QQ;
    }

    public String getStr() {
        return str;
    }

    public void setQQ(String QQ) {
        this.QQ = QQ;
    }

    public void setStr(String str) {
        this.str = str;
    }
}

現在開始抄襲了

		Blog yblog = new Blog();//原部落格
        Blog cblog = new Blog(yblog.title,yblog.text,yblog.referenceLink);//將原部落格抄襲
        System.out.println("原部落格"+yblog);
        System.out.println("抄襲部落格"+cblog);
        System.out.println(yblog.hashCode() == cblog.hashCode());

在這裡插入圖片描述
false表示不相等,抄襲成功
思考,這種方式的弊端。

  1. 太累了,不能一次性全部抄襲,要一步一步來,先標題,後正文等等。
  2. 寫死,部落格可能沒有正文,只有引流連結,程式碼就要修改。

那麼怎麼解決這個問題呢?

利用object的方法,即object.clone。

  • 實現Cloneable
  • 呼叫clone方法
public class Blog implements Cloneable{

    String title = "被抄襲的部落格標題";
    String text = "被抄襲的部落格正文";
    ReferenceLink referenceLink = new ReferenceLink();

    public Blog() {
    }

    public Blog(String title, String text, ReferenceLink referenceLink) {
        this.title = title;
        this.text = text;
        this.referenceLink = referenceLink;
    }

    public String getTitle() {
        return title;
    }

    public String getText() {
        return text;
    }

    public ReferenceLink getReferenceLink() {
        return referenceLink;
    }

    @Override
    public String toString() {
        return "Blog{" +
                "title='" + title + '\'' +
                ", text='" + text + '\'' +
                ", referenceLink=" + referenceLink.QQ + referenceLink.str +
                '}';
    }

    public static void main(String[] args) throws CloneNotSupportedException {

        Blog yblog = new Blog();//原部落格
        Blog cblog = (Blog)yblog.clone();//將原部落格抄襲
        System.out.println("原部落格"+yblog);
        System.out.println("抄襲部落格"+cblog);
        System.out.println(yblog.hashCode() == cblog.hashCode());
    }
}

在這裡插入圖片描述
結果似乎表明也抄襲成功了。

當抄襲者怕被發現將原部落格升級

在這裡插入圖片描述

我們再次執行輸出結果
在這裡插入圖片描述
觀察可知,其實只是克隆了其基本資料型別,參照資料型別並沒有完全克隆,參照資料型別克隆的是參照地址,也就是說當副本改變參照資料型別時,原型也同步改變。

資料型別
在這裡插入圖片描述

深克隆與淺克隆

深克隆: 克隆包括參照型別,開闢新空間,將值填進去
淺克隆: 克隆不包括參照型別,複製的是參照型別的地址

深克隆

ReferenceLink 類

import java.io.Serializable;

public class ReferenceLink implements Cloneable, Serializable {

    String QQ = "qq466009264";
    String str = "來騷擾我呀";

    public String getQQ() {
        return QQ;
    }

    public String getStr() {
        return str;
    }

    public void setQQ(String QQ) {
        this.QQ = QQ;
    }

    public void setStr(String str) {
        this.str = str;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

Blog 類

ublic class Blog implements Cloneable{

    String title = "被抄襲的部落格標題";
    String text = "被抄襲的部落格正文";
    ReferenceLink referenceLink = new ReferenceLink();



    public Blog() {
    }

    public Blog(String title, String text, ReferenceLink referenceLink) {
        this.title = title;
        this.text = text;
        this.referenceLink = referenceLink;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public void setText(String text) {
        this.text = text;
    }

    public void setReferenceLink(ReferenceLink referenceLink) {
        this.referenceLink = referenceLink;
    }

    public String getTitle() {
        return title;
    }

    public String getText() {
        return text;
    }

    public ReferenceLink getReferenceLink() {
        return referenceLink;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Blog blog ;
        blog = (Blog) super.clone();

        blog.referenceLink = (ReferenceLink) referenceLink.clone();
        return blog;
    }

    @Override
    public String toString() {
        return "Blog{" +
                "title='" + title + '\'' +
                ", text='" + text + '\'' +
                ", referenceLink=" + referenceLink.QQ + referenceLink.str +
                '}';
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        Blog yblog = new Blog();//原部落格
        Blog cblog = (Blog)yblog.clone();//將原部落格抄襲
        cblog.setTitle("升級版被抄襲的部落格標題");
        cblog.setText("升級版被抄襲的部落格正文");
        cblog.referenceLink.setQQ("抄襲者的qq");
        cblog.referenceLink.setStr("別來煩我哦");
        System.out.println("原部落格"+yblog);
        System.out.println("抄襲部落格"+cblog);
        System.out.println(yblog.hashCode() == cblog.hashCode());

    }
}

看結果抄襲完全成功
在這裡插入圖片描述
方式一:分別對參照型別賦值克隆
方式二:序列化和反序列化