java設計模式之原型模式

   原型模式是一種比較簡單的設計模式,也非常的容易理解,屬於創建型設計模式的一種,只實現一個接口,重寫一個方法即可完成原型模式。那麼我們就來看看吧。

一、定義

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


二、適用情況

創建一些大對象,比較耗時的對象的時候,可以使用原型模式提高創建對象的效率。


三、原型模式實現

1、實現Cloneable接口,在java中有一個Cloneable接口,它的作用只有一個,就是通知虛擬機可以安全的在實現了此接口的類上使用clone()方法。如果你想看下這個接口,其實可以告訴你,並沒有什麼可看的,只是一個標識接口,實現此接口就是表示了這個類具有被Clone的能力,如果沒有實現此接口,而去使用clone(),就會拋出CloneNotSupportedException異常。

2、重寫Object類中的clone方法。Java中,所有類的父類都是Object類,Object類中有一個clone方法,作用是返回對象的一個拷貝,但是其作用域protected類型的,一般的類無法調用,因此,Prototype類需要將clone方法的作用域修改爲public類型。

下面就以羊來爲原型克隆多利

代碼實現

package cn.wong.pattern.prototype;

import java.util.Date;

public class Sheep implements Cloneable {

    private String name;
    private Date birthDay;


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

    public Sheep() {
    }

    public Sheep(String name, Date birthDay) {
        this.name = name;
        this.birthDay = birthDay;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Date getBirthDay() {
        return birthDay;
    }
    public void setBirthDay(Date birthDay) {
        this.birthDay = birthDay;
    }

}
package cn.wong.pattern.prototype;

import java.util.Date;

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        Sheep s1 = new Sheep("芬蘭母羊",new Date(324324234L));
        System.out.println(s1);
        System.out.println(s1.getName());
        System.out.println(s1.getBirthDay());

        System.out.println("---------進行clone----------");
        Sheep s2 = (Sheep)s1.clone();
        System.out.println(s2);
        System.out.println(s2.getName());
        System.out.println(s2.getBirthDay());
    }
}

結果:

cn.wong.pattern.prototype.Sheep@4633c1aa
芬蘭母羊
Mon Jan 05 02:05:24 CST 1970
---------進行clone----------
cn.wong.pattern.prototype.Sheep@28a50395
芬蘭母羊
Mon Jan 05 02:05:24 CST 1970

從結果可以看出拷貝出來的是一個新的對象,並和原始對象具有相同的屬性值

使用原型模式創建對象比直接new一個對象在性能上要好很多,因爲Object類的clone方法是一個本地方法,它直接操作內存中的二進制流,特別是複製大對象時,性能的差別非常明顯。
protected native Object clone() throws CloneNotSupportedException;

使用原型模式的注意事項

1. 使用原型模式不會調用類的構造方法,因爲它是直接在內存中進行復制的。
2. 深拷貝和淺拷貝


四、淺拷貝和深拷貝

Object類的clone方法只會拷貝對象中的8中基本數據類型,對於數組、日期、容器對象、引用對象等都不會拷貝,這就是淺拷貝。如果要實現深拷貝,必須將原型模式中的數組、容器對象、引用對象等另行拷貝

淺拷貝:

package cn.wong.pattern.prototype;

import java.util.Date;

public class Sheep implements Cloneable {

    private String name;
    private Date birthDay;


    @Override
    public Object clone() throws CloneNotSupportedException {
        Object obj = super.clone();
        /*Sheep s = (Sheep)obj;
        s.birthDay=(Date) this.birthDay.clone();*/
        return obj;
    }

    public Sheep() {
    }

    public Sheep(String name, Date birthDay) {
        this.name = name;
        this.birthDay = birthDay;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Date getBirthDay() {
        return birthDay;
    }
    public void setBirthDay(Date birthDay) {
        this.birthDay = birthDay;
    }

}
package cn.wong.pattern.prototype;

import java.util.Date;

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        Date date = new Date(324324234L);
        Sheep s1 = new Sheep("芬蘭母羊",date);
        System.out.println("---------打印s1的信息----------");
        System.out.println(s1);
        System.out.println(s1.getName());
        System.out.println(s1.getBirthDay());
        //進行復制
        Sheep s2 = (Sheep)s1.clone();


        //修改s1所指向的時間
        date.setTime(23432454354L);
        System.out.println("\n---------再次打印s1的信息----------");
        System.out.println(s1.getName());
        System.out.println(s1.getBirthDay());

        System.out.println("\n---------打印s2的信息----------");
        System.out.println(s2);
        System.out.println(s2.getName());
        System.out.println(s2.getBirthDay());
    }
}

結果:

---------打印s1的信息----------
cn.wong.pattern.prototype.Sheep@5df1cc1a
芬蘭母羊
Mon Jan 05 02:05:24 CST 1970

---------再次打印s1的信息----------
芬蘭母羊
Tue Sep 29 13:00:54 CST 1970

---------打印s2的信息----------
cn.wong.pattern.prototype.Sheep@7a0ec850
芬蘭母羊
Tue Sep 29 13:00:54 CST 1970

發現s2的信息是改變時間後的,我們知道,clone是在修改時間前進行。所以由此我們可以知道引用類型對象不會進行拷貝,s1、s2兩個對象同時都是指向同一個Date,這就是淺拷貝。

深拷貝:

如果要實現深拷貝,必須將引用對象另行拷貝。而對於java的大部分的類都實現了Cloneable接口,所以深拷貝並不困難。

修改Sheep中clone方法

@Override
    public Object clone() throws CloneNotSupportedException {
        Object obj = super.clone();
        Sheep s = (Sheep)obj;
        s.birthDay=(Date) this.birthDay.clone();
        return obj;
    }

測試不變

package cn.wong.pattern.prototype;

import java.util.Date;

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        Date date = new Date(324324234L);
        Sheep s1 = new Sheep("芬蘭母羊",date);
        System.out.println("---------打印s1的信息----------");
        System.out.println(s1);
        System.out.println(s1.getName());
        System.out.println(s1.getBirthDay());
        //進行復制
        Sheep s2 = (Sheep)s1.clone();


        //修改s1所指向的時間
        date.setTime(23432454354L);
        System.out.println("\n---------再次打印s1的信息----------");
        System.out.println(s1.getName());
        System.out.println(s1.getBirthDay());

        System.out.println("\n---------打印s2的信息----------");
        System.out.println(s2);
        System.out.println(s2.getName());
        System.out.println(s2.getBirthDay());
    }
}

結果

---------打印s1的信息----------
cn.wong.pattern.prototype.Sheep@2d8eef25
芬蘭母羊
Mon Jan 05 02:05:24 CST 1970

---------再次打印s1的信息----------
芬蘭母羊
Tue Sep 29 13:00:54 CST 1970

---------打印s2的信息----------
cn.wong.pattern.prototype.Sheep@60813aca
芬蘭母羊
Mon Jan 05 02:05:24 CST 1970
發佈了44 篇原創文章 · 獲贊 15 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章