23種設計模式之原型模式

一、定義

用原型實例指定建立對象的種類,而且經過拷貝這些原型建立新的對象。數組

二、原型模式兩種表現形式

2.1 簡單形式

2.1.1 模式結構bash

原型模式簡單形式由三部分組成:dom

  • 客戶(Client)角色:客戶類提出建立對象的請求。
  • 抽象原型(Prototype)角色:這是一個抽象角色,聲明一個克隆本身的接口。
  • 具體原型(Concrete Prototype)角色:被複制的對象,須要實現抽象的原型角色所要求的接口。

2.1.2 實例ide

2.1.2.1 抽象原型ui

public abstract class Prototype implements Cloneable {
 
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
複製代碼

2.1.2.2 具體原型this

public class ConcretePrototype extends Prototype {
    // 其餘操做
}
複製代碼

2.1.2.3 客戶端調用spa

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Prototype prototype = new ConcretePrototype();
        ConcretePrototype concretePrototype = (ConcretePrototype)prototype.clone();
       
        System.out.println("prototype.hashCode=" + prototype.hashCode());
        System.out.println("concretePrototype.hashCode=" + concretePrototype.hashCode());        
    }
}
複製代碼
2.2 登記形式

2.2.1 模式結構prototype

原型模式登記形式由四部分組成:3d

  • 客戶(Client)角色:客戶類提出建立對象的請求。
  • 抽象原型(Prototype)角色:這是一個抽象角色,聲明一個克隆本身的接口。
  • 具體原型(Concrete Prototype)角色:被複制的對象,須要實現抽象的原型角色所要求的接口。
  • 原型管理器(Prototype Manager)角色:提供各類原型對象的建立和管理。

2.2.2 實例code

2.2.2.1 抽象原型

public abstract class Prototype implements Cloneable {

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
複製代碼

2.2.2.2 具體原型

public class ConcretePrototype extends Prototype {
    // 其餘操做
}
複製代碼

2.2.2.3 原型管理器

public class PrototypeManager {

    private static Map<String, Prototype> map = new HashMap<>();
    
    private PrototypeManager(){
    }
    
    public static void setPrototype(String name, prototype prototype) {
        map.put(name, prototype);
    }
    
    public static void removePrototype(String name) {
        map.remove(name);
    }
    
    public static Prototype getPrototype(String name) throws Exception {
        Prototype prototype = map.get(name);
        
        if (prototype == null) {
            throw new Exception("找不到原型");
        }
        return prototype;
    }
}
複製代碼

2.2.2.4 客戶端調用

public class Test {
    public static void main(String[] args) {
        try {
            Prototype prototype = new ConcretePrototype();
            PrototypeManager.setPrototype("com.freedom.ConcretePrototype", prototype);

            ConcretePrototype concretePrototype = (ConcretePrototype)PrototypeManager.getPrototype("com.freedom.ConcretePrototype").clone();

            System.out.println("prototype.hashcode=" + prototype.hashCode());
            System.out.println("concretePrototype.hashcode=" + concretePrototype.hashCode());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
複製代碼
2.3 兩種形式的比較
  • 若是要建立的原型對象數據較少並且比較固定的話,可採用第一種形式。在這種狀況下,原型對象的引用能夠由客戶端本身保存。
  • 若是要建立的原型對象數據不固定的話,能夠採用第二種形式。在這種狀況下,客戶端不保存對原型對象的引用,這個任務被交給原型管理器角色。在克隆一個對象以前,客戶端能夠查看管理員對象是否已用一個知足要求的原型對象。若是有,能夠從原型管理器角色取得這個對象引用;而後沒有,客戶端就須要自行復制此原型對象。

三、優缺點

3.1 優勢
  • 建立新的對象比較複雜時,能夠利用原型原型模式簡化對象的建立過程,同時也可以提升效率。
  • 不用從新初始化對象,而是動態地得到對象運行時的狀態。
  • 若是原始對象發生變化(增長或者減小屬性),其它克隆對象的也會發生相應的變化,無需修改代碼。
3.2 缺點
  • 每個類都必需要配備一個clone方法。配備clone方法須要對類的功能進行通盤考慮,這對於全新的類來講並非很難,可是對於已有的類來講並不容易。

四、淺克隆和深克隆

4.1 定義
  • Object類的clone()方法使用的是淺克隆。淺克隆對於要克隆的對象,會複製其基本數據類型String類型的屬性的值給新的對象,而對於引用類型,例如數組、集合、引用對象等,僅僅複製一份引用給新產生的對象,即新產生的對象和原始對象中的非基本數據類型的屬性都指向的是同一個對象。
  • 深克隆除了要克隆基本數據類型以外,還須要克隆引用類型的數據。深克隆把要複製的對象所引用的對象都複製了一遍,而這種對被引用到的對象的複製叫作間接複製。
  • 深克隆要深刻到多少層,是一個不易肯定的問題。在決定以深度克隆的方式複製一個對象的時候,必須決定對間接複製的對象時採起淺克隆仍是繼續採用深克隆。所以,在採起深克隆時,須要決定多深纔算深。此外,在深克隆的過程當中,極可能會出現循環引用的問題,必須當心處理。
4.2 實例

4.2.1 被引用的類

public class DeepTarget implements Cloneable, Serializable {

    private String name;

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

    public String getName(String name) {
        return name;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
複製代碼

4.2.2 抽象原型

public abstract class Prototype implements Cloneable {

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
複製代碼

4.2.3 具體原型

public class ConcretePrototype extends Prototype implements Serializable {

    public DeepTarget deepTarget;

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

    // 深克隆,方式一,使用clone方法
    public Object deepCloneOne() throws CloneNotSupportedException {
        ConcretePrototype prototype = (ConcretePrototype) super.clone();
        prototype.deepTarget = (DeepTarget)deepTarget.clone();
        return prototype;
    }

    // 深克隆,方式二,經過對象的序列化實現(推薦)
    public Object deepCloneTwo() throws IOException, ClassNotFoundException {
        // 將對象寫到流裏
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);
        // 從流中讀取出來
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return ois.readObject();
    }
}
複製代碼

4.2.3 客戶端調用

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
        ConcretePrototype prototype = new ConcretePrototype();
        prototype.deepTarget = new DeepTarget();
        prototype.deepTarget.setName("freedom");

        // 淺克隆
        ConcretePrototype concretePrototype = (ConcretePrototype) prototype.clone();
        System.out.println("prototype.hashCode=" + prototype.hashCode() + "\t deepTarget.hashCode=" + prototype.deepTarget.hashCode());
        System.out.println("concretePrototype.hashCode=" + concretePrototype.hashCode() + "\t deepTarget.hashCode=" + concretePrototype.deepTarget.hashCode());
        System.out.println("------------------------------------------------------");

        // 深克隆,方式一
        ConcretePrototype concretePrototype1 = (ConcretePrototype) prototype.deepCloneOne();
        System.out.println("prototype.hashCode=" + prototype.hashCode() + "\t deepTarget.hashCode=" + prototype.deepTarget.hashCode());
        System.out.println("concretePrototype1.hashCode=" + concretePrototype1.hashCode() + "\t deepTarget.hashCode=" + concretePrototype1.deepTarget.hashCode());
        System.out.println("------------------------------------------------------");

        // 深克隆,方式二
        ConcretePrototype concretePrototype2 = (ConcretePrototype) prototype.deepCloneTwo();
        System.out.println("prototype.hashCode=" + prototype.hashCode() + "\t deepTarget.hashCode=" + prototype.deepTarget.hashCode());
        System.out.println("concretePrototype2.hashCode=" + concretePrototype2.hashCode() + "\t deepTarget.hashCode=" + concretePrototype2.deepTarget.hashCode());
    }
}
複製代碼

特別聲明:一、如若文中有錯之處,歡迎大神指出。 二、文章是參考網上一些大神的文章,本身整理出來的,如如有侵權,可聯繫我刪除。

相關文章
相關標籤/搜索