05 原型模式

定義

原型模式(Prototype):使用原型實例指定待創建對象的類型,並且通過複製這個原型來創建新的對象。

結構

  1. Porototype(抽象原型類):它是聲明克隆方法的接口,是所有具體原型類的公共父類,它可以是接口,甚至可以是具體實現類。
  2. ConcretePrototype(具體原型類):它實現在抽象原型類中聲明的克隆方法,在克隆方法中返回自己的一個克隆對象。
  3. Client(客戶類):在客戶類中,讓一個原型對象克隆自身從而創建一個新的對象,只需要直接實例化或通過工廠方法等方式創建一個原型對象,再通過調用該對象的克隆方法即可得到多個相同的對象。由於客戶類針對抽象原型類Portotype編程,因此用戶可以根據需要選擇的具體原型類,系統具有較好的可擴展性,增加或更換具體原型類都很方便。

淺克隆與深克隆

  • 淺克隆
    在淺克隆中,如果原型對象的成員變量是值類型(如int、double、byte、boolean、char等基本數據類型),將複製一份給克隆對象;如果原型對象的成員變量是引用類型(如類、接口、數組等複雜數據類型),則將引用對象的地址複製一份給克隆對象,也就是說原型對象和克隆對象的成員變量指向相同的內存地址。簡單來說,在淺克隆中,當原型對象被複制時只複製它本身和其中包含的值類型的成員變量,而引用類型的成員變量並沒有複製。
  • 深克隆
    在深克隆中,無論原型對象的成員變量是值類型還是引用類型,都將複製一份給克隆對象,深克隆將原型對象的所有引用對象也複製一一份給克隆對象。簡單來說,在深克隆中,除了對象本省被複制外,對象所包含的所有成員變量也將複製被複制。

代碼

抽象原型

public abstract class Prototype {

    public abstract Prototype clone();

}

public class ConcretePrototype extends Prototype {

private String attr;

@Override
public Prototype clone() {
    ConcretePrototype prototype = new ConcretePrototype();
    prototype.setAttr(attr);
    return prototype;
}

public String getAttr() {
    return attr;
}

public void setAttr(String attr) {
    this.attr = attr;
}

}


客戶端調用

public class Client {

public static void main(String[] args) {
    ConcretePrototype prototype =  new ConcretePrototype();
    prototype.setAttr("name");

    ConcretePrototype concretePrototype = (ConcretePrototype) prototype.clone();
    System.out.println(concretePrototype.getAttr());
}

}

執行結果

name

Java中的clone()方法和Cloneable接口

public class ConcretePrototype1 implements Cloneable {

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone(); // 淺克隆
    }

}
原型管理器

將多個原型對象儲存在一個集合中供客戶端使用,它是一個專門負責克隆對象的工廠,其中定義了一個集合對象用於存儲原型對象,如果需要某個原型對象的一個克隆,可以通過複製集合中對象的原型對象來獲取。

import java.util.Hashtable;
import java.util.Map;

public class PortotypeManager {
    
    private Map<String, Prototype> prototypeMap = new Hashtable<>();

    public PortotypeManager() {
        prototypeMap.put("A", new ConcretePrototypeA());
        prototypeMap.put("B", new ConcretePrototypeB());
    }
    
    public void add(String key, Prototype prototype) {
        prototypeMap.put(key, prototype);
    }
    
    public Prototype get(String key) {
        return prototypeMap.get(key).clone();
    }
    
}

優/缺點與適用環境

  • 優點
  1. 當創建新的對象實例較爲複雜時,適用原型模式可以簡化對象的創建過程,通過複製一個已有的實例可以提高新實例的創建效率。
  2. 擴展性好,由於在原型模式中提供了抽象原型類,在客戶端可以針對抽象原型類進行編程,而降具體原型類寫在配置文件中,增加或減少產品類對原有系統沒有任何影響。
  3. 原型模式提供簡化的創建結構,工廠方法模式常常需要一個產品類等級結構相同的工廠等級結構,而原型模式就不需要這樣,原型模式中產品的複製時通過封裝在原型類中的克隆方法實現的,無須專門的工廠類來創建產品。
  4. 可以通過深克隆的方式保存對象的狀態,使用原型模式將對象複製一份並將其狀態保存起來,以便在需要的時候使用(例如恢復到某一歷史狀態),可輔助實現撤銷操作。
  • 缺點
  1. 需要爲每一個原型類配備一個克隆方法,而且該克隆方法位於一個類的內部,當對已有的類進行改造時需要修改源代碼,違背了開閉原則。
  2. 在實現深克隆的時候需要編寫較爲複雜的代碼,而且當對象之間存在多重的嵌套引用時,爲了實現深克隆,每一層對象對應的類都必須支持深克隆,實現起來可能會比較麻煩。
  • 適用環境
  1. 創建對象的成本較大(例如初始化需要佔用較長的時間、佔用太多的CPU資源或者網絡資源),新對象可以通過複製已有對象來獲得,如果是相似對象,則可以對其成員變量稍作修改。
  2. 系統需要保存對象的狀態,而對象的狀態變化很小。
  3. 需要避免使用分層次的工廠類來創建分層次的對象,並且類的實例對象只有一個或者很少的幾個組合狀態,通過複製原型對象得到新實例可能比使用構造函數來創建一個實例更加方便。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章