原型模式—創建型

簡介:

原型二字說明了該模式應該有一個樣板實例,用戶從這個樣板對象複製(克隆)出一個內部屬性一致的對象。被複制的實例就是原型。如果對象的創建成本比較大,而同一個類的不同對象之間差別不大(大部分字段都相同),在這種情況下,我們可以利用對已有對象(原型)進行復制(或者叫拷貝)的方式來創建新對象,以達到節省創建時間的目的。這種基於原型來創建對象的方式就叫作原型設計模式(Prototype Design Pattern),簡稱原型模式。

應用場景

1,類初始化需要很消耗資源,通過原型複製創建對象,可以避免這些資源消耗;

2,通過new創建一個對象需要很繁瑣的數據準備,可通過原型模式;

3,一個類的不同對象之間差別不大,大部分字段都相同;

實現

對於熟悉 JavaScript 語言的前端程序員來說,原型模式是一種比較常用的開發模式。這是因爲,有別於 Java、C++ 等基於類的面向對象編程語言,JavaScript 是一種基於原型的面向對象編程語言。在Java語言中,最簡單的實現就是調用的clone()方法;

案例:

原型

Book.class爲原型,複製出更多的Book對象;

import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;

public class Book implements Cloneable{

    private String name;
    private ArrayList<String> mImages = new ArrayList<>();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<String> getImages() {
        return mImages;
    }

    public void setImage(String image) {
        this.mImages.add(image);
    }

    public void showConten() {
        System.out.println("**************** Start **************");
        System.out.println("name: "+ this.name);

        for (String img : mImages) {
            System.out.println("image name: " + img);
        }
        System.out.println("**************** End **************");
    }

    @NonNull
    @Override
    protected Book clone() {
        try {
            Book book = (Book) super.clone();
            book.name = this.name;
            book.mImages = this.mImages;
            return book;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }
}

複製對象

public class CloneBook {

    public static void main(String[] args) {
        Book book = new Book();
        book.setName("活法");
        book.setImage("圖1");
        book.setImage("圖2");

        book.showConten();

        Book book1 = book.clone();
        book1.setName("Android");
        book1.showConten();

        book.showConten();
    }
}

 運行:

**************** Start **************
name: 活法
image name: 圖1
image name: 圖2
**************** End **************
**************** Start **************
name: Android
image name: 圖1
image name: 圖2
**************** End **************
**************** Start **************
name: 活法
image name: 圖1
image name: 圖2
**************** End **************
 

淺拷貝和深拷貝

原型模式有兩種實現方法,深拷貝和淺拷貝。不管淺拷貝還是深拷貝都是原型模式的實現方式;

淺拷貝:淺拷貝只會複製對象中基本數據類型數據和引用對象的內存地址,不會遞歸地複製引用對象,以及引用對象的引用對象;

上面的Book對象的拷貝就是淺拷貝,不信可以試試,代碼如下

public class CloneBook {

    public static void main(String[] args) {
        Book book = new Book();
        book.setName("活法");
        book.setImage("圖1");
        book.setImage("圖2");

        book.showConten();

        Book book1 = book.clone();
        book1.setName("Android");
        book1.setImage("圖3");//修改引用對象的數據
        book1.showConten();

        book.showConten();
    }
}

 運行結果:

**************** Start **************
name: 活法
image name: 圖1
image name: 圖2
**************** End **************
**************** Start **************
name: Android
image name: 圖1
image name: 圖2
image name: 圖3
**************** End **************
**************** Start **************
name: 活法
image name: 圖1
image name: 圖2
image name: 圖3
**************** End **************

可以看出拷貝的對象book1修改了原型中的引用對象的數據(mImages),結果book對象中的引用對象的數據也改變了;book和book1同時指向mImages的同一個對象地址;

深拷貝:深拷貝得到的是一份完完全全獨立的對象。

修改Book類中的clone方法

@NonNull
@Override
protected Book clone() {
     try {
         Book book = (Book) super.clone();
         book.name = this.name;
         book.mImages = (ArrayList<String>) this.mImages.clone();
         return book;
     } catch (CloneNotSupportedException e) {
         e.printStackTrace();
     }
     return null;
}

重新運行如下代碼

public class CloneBook {

    public static void main(String[] args) {
        Book book = new Book();
        book.setName("活法");
        book.setImage("圖1");
        book.setImage("圖2");

        book.showConten();

        Book book1 = book.clone();
        book1.setName("Android");
        book1.setImage("圖3");//修改引用對象的數據
        book1.showConten();

        book.showConten();
    }
}

結果:book1修改了引用類型對象中的數據,對book沒有任何影響;這就是深拷貝;

**************** Start **************
name: 活法
image name: 圖1
image name: 圖2
**************** End **************
**************** Start **************
name: Android
image name: 圖1
image name: 圖2
image name: 圖3
**************** End **************
**************** Start **************
name: 活法
image name: 圖1
image name: 圖2
**************** End **************

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章