原型模式


原型模式算是JAVA中最簡單的設計模式了,原因是因為它已經被提供了語言級的支持,但是如果提到它的實現原理,又是最復雜的一個設計模式。

(1)先看一下原型模式的UML類圖

  其中,Prototype是一個原型的抽象類或借口,它里面有一個共有方法,叫clone。ConcretePrototype1與ConcretePrototype2是兩個具體的實例,繼承或實現了Prototype。這就對應了定義中用原型實例指定創建對象的種類。Client是客戶端類,它與Prototype是關聯的關系,即在Client類的實例中,有Prototype的對象。客戶端可以通過調用Prototype的clone方法來對實現了Prototype的ConcretePrototype1或ConcretePrototype2的對象進行復制來創建新對象,這樣比new會有更高的執行效率。

 

(2)下面我們先來看看這個又簡單又復雜的設計模式的定義

定義:用原型實例指定創建對象的種類,並且通過拷貝這些原型創建新的對象。

定義比較簡單,總結一下是通過實例指定種類,通過拷貝創建對象。

在JAVA語言中使用原型模式是非常簡單的,這是因為Object類當中提供了一個本地方法clone,而JAVA中的任何類只要實現了Cloneable標識接口,就可以使用clone方法來進行對象的拷貝。

我們寫一個簡單的實例來測試一下,很簡單:

public class Prototype implements Cloneable {
 
        private int x;
 
        private int y;
 
        private int z;
 
        public Prototype() {
 
                this.x = 2;
 
                this.y = 3;
 
                this.z = 4;
 
        }
 
        public void change() {
 
                this.x = 9;
 
                this.y = 8;
 
                this.z = 7;
 
        }
 
        public Prototype clone() {
 
                Object object = null;
 
                try {
 
                        object = super.clone();
 
                } catch (CloneNotSupportedException exception) {
 
                        throw new RuntimeException(exception);
 
                }
 
                return (Prototype) object;
 
        }
 
        public String toString() {
 
                return "[" + x + "," + y + "," + z + "]";
 
        }
 
        public static void main(String[] args) {
 
                Prototype prototype1 = new Prototype();
 
                prototype1.change();
 
                System.out.println(prototype1);
 
                Prototype prototype2 = prototype1.clone();
 
                System.out.println(prototype2);
 
        }
 
}
 

輸出結果:

  [9,8,7]

  [9,8,7] 

   從輸出結果可以看出來,clone方法將prototype1復制了一個,然后賦給了prototype2,這就像復制粘貼一樣。值得注意的是,在使用Object.clone()方法去拷貝一個對象時,構造方法是不被執行的,否則prototype2實例中x,y,z的值應該為2,3,4才對,如果你覺得不夠直觀,可以在構造方法里寫一個輸出語句試試。

(3)從原型模式的使用方式不難推斷出,原型模式常使用於以下場景:

       1、對象的創建非常復雜,可以使用原型模式快捷的創建對象。

       2、在運行過程中不知道對象的具體類型,可使用原型模式創建一個相同類型的對象,或者在運行過程中動態的獲取到一個對象的狀態。

對於clone方法,它執行的是淺拷貝,也就是說如果是引用類型的屬性,則它不會進行拷貝,而是只拷貝引用。

       看下面這個簡單的測試,就能看出來了。

class Field implements Cloneable{       
 
        private int a;
 
        public int getA() {
 
                return a;
 
        }
 
        public void setA(int a) {
 
                this.a = a;
 
        }
 
       
 
        protected Field clone() {
 
                Object object = null;
 
                try {
 
                        object = super.clone();
 
                } catch (CloneNotSupportedException exception) {
 
                        throw new RuntimeException(exception);
 
                }
 
                return (Field) object;
 
        }
 
       
 
}
 
 
 
public class DeepPrototype implements Cloneable {
 
        private int x;
 
        private int y;
 
        private int z;
 
        private Field field;
 
        public DeepPrototype() {
 
                this.x = 2;
 
                this.y = 3;
 
                this.z = 4;
 
                this.field = new Field();
 
                this.field.setA(5);
 
        }
 
       
 
        public Field getField() {
 
                return field;
 
        }
 
        protected DeepPrototype clone() {
 
                Object object = null;
 
                try {
 
                        object = super.clone();
 
                        ((DeepPrototype)object).field = this.field.clone();
 
                } catch (CloneNotSupportedException exception) {
 
                        throw new RuntimeException(exception);
 
                }
 
                return (DeepPrototype) object;
 
        }
 
        public String toString() {
 
                return "[" + x + "," + y + "," + z + "," + field.getA() + "]";
 
        }
 
        public static void main(String[] args) {
 
                DeepPrototype prototype1 = new DeepPrototype();
 
                System.out.println(prototype1);
 
                System.out.println(prototype1.getField());
 
                DeepPrototype prototype2 = prototype1.clone();
 
                System.out.println(prototype2);
 
                System.out.println(prototype2.getField());
 
        }
 
}

輸出結果:

  [2,3,4,5]

  com.prototype.Field@a90653

  [2,3,4,5]

  com.prototype.Field@de6ced

(4)下面我們來看下原型模式的主要優點:

        1、由於clone方法是由虛擬機直接復制內存塊執行,所以在速度上比使用new的方式創建對象要快。

        2、可以基於原型,快速的創建一個對象,而無需知道創建的細節。

        3、可以在運行時動態的獲取對象的類型以及狀態,從而創建一個對象。

  然而原型模式的缺點也是相當明顯的,主要的缺點就是實現深度拷貝比較困難,需要很多額外的代碼量。

       不過實際當中我們使用原型模式時,也可以寫一個基類實現Cloneable接口重寫clone方法,然后讓需要具有拷貝功能的子類繼承自該類,這是一種節省代碼量的常用方式。像上面的例子一樣,如果一個類繼承自Prototype,則會自動具有拷貝功能。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM