創(chuàng)建型設(shè)計模式之單例,工廠方法,抽象工廠,策略,建造者,原型

1:單例模式

只能有一個實例

推薦:靜態(tài)內(nèi)部類單例模式

理由:靜態(tài)內(nèi)部類,當(dāng)你使用它的時候才加載,這種方式不僅能夠確保線程安全,也能夠保證單例對象的唯一性,同時也延遲了單例的實例化,所以推薦使用

public class Singleton {
    
    private Singleton(){}
    /**
     *    類級的內(nèi)部類,也就是靜態(tài)的成員式內(nèi)部類,該內(nèi)部類的實例與外部類的實例
     *    沒有綁定關(guān)系,而且只有被調(diào)用到時才會裝載,從而實現(xiàn)了延遲加載。
     */
    private static class SingletonHolder{
        /**
         * 靜態(tài)初始化器,由JVM來保證線程安全
         */
        private static Singleton instance = new Singleton();
    }
    
    public static Singleton getInstance(){
        return SingletonHolder.instance;
    }
}

優(yōu)缺點:
單例只有在使用時才會被實例化,在一定程度上節(jié)約了資源

單例類的職責(zé)過重,里面的代碼可能會過于復(fù)雜,在一定程度上違背了“單一職責(zé)原則”

Android中單例對象如果持有Context,那么很容易引發(fā)內(nèi)存泄露,此時需要注意傳遞給單例對象的Context最好是Application Context

參考:
《JAVA與模式》之單例模式
《Android源碼設(shè)計模式》--單例模式

2:簡單工廠模式

產(chǎn)品抽象實現(xiàn)多態(tài),而工廠單一的模式

一個工廠,一個抽象產(chǎn)品,多個產(chǎn)品子類
簡單工廠模式不是 23 種里的一種,簡而言之,就是有一個專門生產(chǎn)某個產(chǎn)品的類

3:工廠方法模式

產(chǎn)品抽象實現(xiàn)多態(tài),且工廠抽象實現(xiàn)多態(tài)的模式

一個抽象工廠,多個工廠子類,一個抽象產(chǎn)品和多個產(chǎn)品子類

和簡單工廠的區(qū)別:將工廠也抽象,避免了當(dāng)產(chǎn)品過多,一個工廠的復(fù)雜性

更符合開-閉原則
符合單一職責(zé)原則
不使用靜態(tài)工廠方法,可以形成基于繼承的等級結(jié)構(gòu)。

4:抽象方法模式

工廠升級,需要生產(chǎn)多個方向的不同產(chǎn)品,需要將產(chǎn)品進(jìn)一步抽象

就是抽象,可拓展,進(jìn)一步抽象,不妨使用“接口”。

抽象工廠模式與工廠方法模式的最大區(qū)別就在于,工廠方法模式針對的是一個產(chǎn)品等級結(jié)構(gòu);而抽象工廠模式則需要面對多個產(chǎn)品等級結(jié)構(gòu)。

image.png

優(yōu)點:新增工廠容易擴(kuò)展
缺點: 如果是新的產(chǎn)品,需要修改抽象工廠,從而修改所有工廠子類

參考: 《JAVA與模式》之抽象工廠模式

5:建造者模式

復(fù)雜對象的創(chuàng)建和他的表現(xiàn)分離,可以生產(chǎn)很多不同表現(xiàn)的對象

通常會將Builder設(shè)計為鏈?zhǔn)秸{(diào)用,他的關(guān)鍵點是每個setter方法都返回自身,也就是return this,這樣就使得setter方法可以鏈?zhǔn)秸{(diào)用

參考:Builder模式

builder模式另一個重要特性是:它可以對參數(shù)進(jìn)行合法性驗證

/**
         * 創(chuàng)建外部類person
         * @return
         */
        public Person create(){

            Person person = new Person(this);

            //線程不安全的,所以需要對象創(chuàng)建之后進(jìn)行合法性驗證
            if(person.age > 40){
                throw new IllegalStateException("年齡超過限制!");
            }

            return person;
        }

參考:Android設(shè)計模式之建造者模式(builder pattern)

缺點:會產(chǎn)生多余的Builder對象以及Director對象,消耗內(nèi)存

         對象的構(gòu)建過程暴露

參考: 《Android源碼設(shè)計模式》--Builder模式

6:原型模式

要求對象實現(xiàn)一個可以“克隆”自身的接口,通過一個實例對象本身來創(chuàng)建一個新的實例

如下:通過調(diào)用operation(Prototype example)方法傳入不同的實例對象,克隆一個新的對象,而且可以更加傳入的不同實例創(chuàng)建不同的對象的實例對象。

public class Client {
    /**
     * 持有需要使用的原型接口對象
     */
    private Prototype prototype;
    /**
     * 構(gòu)造方法,傳入需要使用的原型接口對象
     */
    public Client(Prototype prototype){
        this.prototype = prototype;
    }
    public void operation(Prototype example){
        //需要創(chuàng)建原型接口的對象
        Prototype copyPrototype = prototype.clone();
        
    }
}

java 的克隆過程,存在一個淺度克隆和深度克隆的問題

淺度克隆:不復(fù)制它所引用的對象
深度克隆:除了淺度克隆要克隆的值外,還負(fù)責(zé)克隆引用類型的數(shù)據(jù)。那些引用其他對象的變量將指向被復(fù)制過的新對象,而不再是原有的那些被引用的對象。換言之,深度克隆把要復(fù)制的對象所引用的對象都復(fù)制了一遍,而這種對被引用到的對象的復(fù)制叫做間接復(fù)制
方法:可以利用序列化實現(xiàn)深度克隆

適用場景

~創(chuàng)建新對象成本較大(如初始化占用較長的時間,占用太多CPU或網(wǎng)絡(luò)資源)
~如果系統(tǒng)要保存對象的狀態(tài),而對象的狀態(tài)變化很小

參考:
java設(shè)計模式之原型模式
JAVA與模式之原型模式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容