單例模式及相關(guān)的空指針的思考

單例模式的討論珠玉在前,我就不過多敘述基礎(chǔ)的內(nèi)容。感興趣的朋友可以閱讀參考資料1。


假設(shè)現(xiàn)在有一種變形的餓漢式單例,單例的賦值是在類的構(gòu)造函數(shù)里面進行的。樣例代碼如下:

public class SingletonSample{
    private static SingletonSample mInstance;
    private SingletonSample(String arg){
        mInstance = this;
    }
    public static SingletonSample getInstance(){
        return mInstance;
    }
    public void doSomething(){
        //做一些事情
        ...
    }
}

那么上文的getInstance函數(shù)是不能保證返回值非空的。那在程序中就有可能出現(xiàn)空指針,進而導致崩潰。
限制單例的賦值不能變換位置的話,現(xiàn)在有兩種解決方案擺在我們面前:

  1. getInstance方法不保證非空,在外部任一調(diào)用getInstance函數(shù)的地方先進行非空判定再執(zhí)行相關(guān)方法。
  2. getInstance方法保證非空

顯然方案一是不需要更多思考的,直接就是空指針情形的常見解決方案,判空,非空則執(zhí)行邏輯,否則不執(zhí)行。但這種解決方案我覺得不好,既要修改已有的很多個調(diào)用處,即多個文件,還要保證之后調(diào)用的地方都自覺加上非空判定。
所以我選擇方案二。但是根據(jù)限制條件“單例的賦值不能變換位置”,自然是不能把當前這個單例轉(zhuǎn)為標準的餓漢式或懶漢式。既然不能隨意改動到mInstance的值,那有沒有別的方法達成getInstance方法保證非空的目的呢?
哈哈哈哈,當然有啦,mInstance為null的時候返回一個空的占位符實例不就行了嗎
修改后的樣例代碼如下:

public class SingletonSample{
    private static SingletonSample mInstance;
    private static final SingletonSample PLACEHOLDER = new SingletonSample() ;
    private SingletonSample(){
        //空的構(gòu)造函數(shù),純粹為了占位符而生
    }
    private SingletonSample(String arg){
        mInstance = this;
    }
    public static SingletonSample getInstance(){
        if (mInstance == null) {
            return PLACEHOLDER;
        }
        return mInstance;
    }
    public void doSomething(){
        if(!isValidInstance()){
            return;
        }
        //做一些事情
        ...
    }
    private boolean isValidInstance(){
        return this != PLACEHOLDER;
    }
}

這其實也是空指針情形的一種常見解決方案,空的時候返回一個默認值/占位符,不空的時候返回實際值。

可以看到還加了個isValidInstance的判斷函數(shù),原因是實際邏輯操作的時候,可能占位符/默認值并不能執(zhí)行,所以要在所有的對外方法中添加實例檢查。

這樣修改后,其實還是不可避免地要進行多處修改,但這次的多處修改都是在當前單例類里面的,不會涉及外部類;同時也是要保證之后當前單例類里新增的對外實例方法,都要進行實例驗證才能進行邏輯操作,但是這仍舊是當前類里的修改,不涉及外部類。

這個解決方案在我看來,雖然還有類似的限制(要改動多處,對之后的邏輯有要求),但是還是比第一種解決方案要優(yōu)秀,因為外部調(diào)用處有可能不是同一個開發(fā)者書寫的邏輯;但把限制都約束在了同一個類里,既避免了空指針發(fā)散,也在很多情況下是同一個開發(fā)者維護的邏輯,更能避免后續(xù)Bug的產(chǎn)生。

看回PLACEHOLDER這個靜態(tài)變量,它會不會有可能為null呢?

不會。

這個變量的賦值是在類初始化的時候,這個值為null的話,只有可能是相關(guān)的ClassLoader都被銷毀了,否則只要這個類有加載到ClassLoader中初始化,這個變量就都不會為null。詳細參見參考資料2。


參考資料

  1. 單例這種設(shè)計模式 - 技術(shù)小黑屋
  2. Are static fields open for garbage collection? - Stack Overflow
最后編輯于
?著作權(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)容