Android設(shè)計模式之(3)----原型模式

原型模式


用原型實例指定創(chuàng)建對象的,拷貝這些對象生成新的對象進行使用。

也可以直接進行new一個對象,但是當對象的構(gòu)造復雜時,new的效率會很低,使用clone更好

new適用于簡單的構(gòu)造

clone適用于復雜的構(gòu)造

應(yīng)用場景

  • 資源消耗大的對象
  • 節(jié)省資源,比如在for循環(huán)內(nèi)創(chuàng)建相同的對象
  • 一個對象要讓其他人使用,并且使用過程中要改變這個對象的某些屬性,可考慮將原有對象拷貝,并且修改需要改變的屬性,在進行使用
  • 對象結(jié)構(gòu)復雜的情況使用拷貝

淺拷貝代碼實現(xiàn)

<font color=#0099ff size=3 face="黑體">原型對象實現(xiàn)Cloneable接口</font>(默認是淺拷貝

class Prototype implements Cloneable {

    public Prototype clone() {
        Prototype prototype = null;
        try {
            prototype = (Prototype) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return prototype;
    }


}

原型對象具體的內(nèi)容實現(xiàn)

class ConcretePrototype extends Prototype {

    public String name;
    public ArrayList<String> list = new ArrayList<>();

    public ConcretePrototype() {
        System.out.println("執(zhí)行了ConcretePrototype構(gòu)造函數(shù)");
    }

    @Override
    public String toString() {
        return "ConcretePrototype{" +
                "name='" + name + '\'' +
                ", list=" + list +
                '}';

    }


    public void show() {
        System.out.println("原型模式實現(xiàn)類");
    }
}   

使用方式

  ConcretePrototype cp = new ConcretePrototype();
        cp.name = "原始數(shù)據(jù)";
        for (int i = 0; i < 10; i++) {
            cp.list.add(i, String.valueOf(i));//填充數(shù)據(jù)
        }
        ConcretePrototype cloneConcretePrototype = (ConcretePrototype) cp.clone();//實現(xiàn)拷貝
        cloneConcretePrototype.name = "拷貝數(shù)據(jù)";
        System.out.println(cp.toString());
        System.out.println(cloneConcretePrototype.toString());
        

顯示結(jié)果:

執(zhí)行了ConcretePrototype構(gòu)造函數(shù)
ConcretePrototype{name='原始數(shù)據(jù)', list=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}
ConcretePrototype{name='拷貝數(shù)據(jù)', list=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}

<font color=#0099ff size=3 face="黑體">原型對象不實現(xiàn)Cloneable接口</font>(默認是淺拷貝

其實就是把cloneable接口的內(nèi)容手動實現(xiàn)一次

class ConcretePrototype2 {

    public String name;
    public ArrayList<String> list = new ArrayList<>();

    public ConcretePrototype2() {
        System.out.println("執(zhí)行了ConcretePrototype2構(gòu)造函數(shù)");
    }

    public ConcretePrototype2 clone() {
       //手動new對象進行賦值
        concretePrototype2 concretePrototype2 = new ConcretePrototype2();
        concretePrototype2.name = this.name;
        concretePrototype2.list = this.list;
        return concretePrototype2;
    }


    @Override
    public String toString() {
        return "ConcretePrototype2{" +
                "name='" + name + '\'' +
                ", list=" + list +
                '}';

    }


    public void show() {
        System.out.println("原型模式實現(xiàn)類");
    }
}

調(diào)用方式

 ConcretePrototype2 cp = new ConcretePrototype2();
        cp.name = "原始數(shù)據(jù)";
        for (int i = 0; i < 10; i++) {
            cp.list.add(i, String.valueOf(i));//填充數(shù)據(jù)
        }
        ConcretePrototype2 cloneConcretePrototype = (ConcretePrototype2) cp.clone();//實現(xiàn)拷貝
        cloneConcretePrototype.name = "拷貝數(shù)據(jù)";
        System.out.println(cp.toString());
        System.out.println(cloneConcretePrototype.toString());

顯示結(jié)果

執(zhí)行了ConcretePrototype2構(gòu)造函數(shù)
執(zhí)行了ConcretePrototype2構(gòu)造函數(shù)
ConcretePrototype2{name='原始數(shù)據(jù)', list=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}
ConcretePrototype2{name='拷貝數(shù)據(jù)', list=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}

構(gòu)造函數(shù)執(zhí)行了兩次,說明了cloneable接口的復制是不會執(zhí)行2次構(gòu)造的,直接new對象則會調(diào)用2次構(gòu)造。

測試

修改復制后的數(shù)據(jù)

 ConcretePrototype2 cp = new ConcretePrototype2();
        cp.name = "原始數(shù)據(jù)";
        for (int i = 0; i < 10; i++) {
            cp.list.add(i, String.valueOf(i));//填充數(shù)據(jù)
        }
        ConcretePrototype2 cloneConcretePrototype = (ConcretePrototype2) cp.clone();//實現(xiàn)拷貝
        cloneConcretePrototype.name = "拷貝數(shù)據(jù)";
        cloneConcretePrototype.list.add("追加測試數(shù)據(jù)");
        System.out.println(cp.toString());
        System.out.println(cloneConcretePrototype.toString());

顯示結(jié)果

執(zhí)行了ConcretePrototype2構(gòu)造函數(shù)
執(zhí)行了ConcretePrototype2構(gòu)造函數(shù)
ConcretePrototype2{name='原始數(shù)據(jù)', list=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 追加測試數(shù)據(jù)]}
ConcretePrototype2{name='拷貝數(shù)據(jù)', list=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 追加測試數(shù)據(jù)]}

【追加測試數(shù)據(jù)無論是原型還是拷貝后的對象都有這個數(shù)據(jù)】

問題原因:深拷貝-淺拷貝

Cloneable接口默認實現(xiàn)的是淺拷貝,對于基本類型會進行拷貝,但是對于引用類型(集合,數(shù)據(jù),對象)等clone僅僅代表指向了同一個內(nèi)存地址,所以修改一個兩個都會變化。

解決方案:在引用類型的具體數(shù)據(jù)類型在進行一次clone,將淺拷貝處理為深拷貝

深拷貝代碼實現(xiàn)

代碼如下

  public ConcretePrototype2 clone() {
        //手動new對象進行賦值
//        ConcretePrototype2 concretePrototype2 = new ConcretePrototype2();
//        concretePrototype2.name = this.name;
//        concretePrototype2.list = this.list;
//        return concretePrototype2;
        
        //將具體的集合修改為深拷貝
        ConcretePrototype2 concretePrototype2 = new ConcretePrototype2();
        concretePrototype2.name = this.name;
        concretePrototype2.list = (ArrayList<String>) this.list.clone();

        return concretePrototype2;

    }
    

顯示結(jié)果

執(zhí)行了ConcretePrototype2構(gòu)造函數(shù)
執(zhí)行了ConcretePrototype2構(gòu)造函數(shù)
ConcretePrototype2{name='原始數(shù)據(jù)', list=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}
ConcretePrototype2{name='拷貝數(shù)據(jù)', list=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 追加測試數(shù)據(jù)]}

應(yīng)證我們的想法,對于集合,數(shù)組,對象等,如果要新增數(shù)據(jù),需要對其重寫更改具體的數(shù)據(jù)類型。

總結(jié)

原型模式可以避免構(gòu)造復雜的對象時的資源消耗問題,提升創(chuàng)建對象的效率。
可以保護原始對象的數(shù)據(jù)安全性
clone是二進制流,對于復雜的構(gòu)造對象,性能提升明顯,但是對于簡單的構(gòu)造沒必要使用clone

github代碼地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容