Offensive Coding(進攻編碼)

參考自:http://www.artima.com/weblogs/viewpost.jsp?thread=168511程序員

   一直以來只知道防護式編程,《代碼大全》中也專門有一章講述防護式編程,防護式編程又稱被動編程。有一個比喻是說開車時司機只遵照交通規則是遠遠不夠的,還得時刻提防其餘意外因素,如馬路殺手、其餘醉酒的司機等等。對應在編程中就是「不能信任用戶的輸入,必須執行相應的參數檢查」。web

   而offensive coding則與此相反,它的中文意思是攻擊式編程或者主動編程。編程

   先看一段簡單的代碼:數組

private void addResolution(List<Flag> flags) {
    if (flags != null) {
        if (supportedAdapters.contains(Adapter.LOW) 
                || supportedAdapters.contains(Adapter.MEDIUM)) {
            flags.add(new ResolutionFlag(ADAPTED));
        } 
    }
}

   這段代碼有啥問題?也許有人的第一反應是這段代碼應該使用Guard Clause,即改爲下面這樣:jsp

private void addResolution(List<Flag> flags) {
    if(flags == null)
        return;

    if (supportedAdapters.contains(Adapter.LOW) 
                || supportedAdapters.contains(Adapter.MEDIUM)) {
        flags.add(new ResolutionFlag(ADAPTED));
    }
}

   但其實問題不在於此,而在於這一行代碼:post

if(flags == null) {...

   既然是private方法,那麼徹底能夠在類內部本身保證傳入的參數flags不爲null,而不用進行多餘的null check。code

濫用null check是糟糕代碼的標識。

   null check是不可或缺的。若是你在你的代碼中處處傳遞null,那麼接收參數並處理的方法進行null check是必要的。可是這也意味着你的代碼很糟糕。你在給本身增長額外負擔(全部有參數的方法開頭都必須進行null check),你的代碼也很難複用。blog

   另一個例子:get

public String [] getParameters() {
    if (intParms.length  == 0) {
        return null;
    }
    String [] result = new String[intParms.length];
    for(int n = 0; n < intParms.length; n++) {
        result[n] = "parameter " + intParms[n];
    }
    return result;
}

   這段代碼有什麼問題呢?若是這個方法被你本身在同一個項目中其餘地方使用還好,你知道返回值可能爲null,因此你會進行null check。而若是是你的同事在使用這段代碼,或者這段代碼被打包在Jar中被世界上某個角落的另外一個程序員使用呢?他們不會像你同樣對你的代碼這麼熟悉。他們極可能忘記null check,好比以下:io

// 世界上某個角落的其餘程序員Fork在使用你的Jar包中的getParameters方法
public void foo() {
   ...
   int len = new ConcreteService().getParameters().length;
   ...
}

   極可能這段代碼在大部分狀況下都能正常運行,而不會拋出NullPointerException,因而這位程序員又將這段代碼打包到他的Jar包裏,以後又有第三個程序員John來使用Fork的Jar包中的foo()方法,以下:

// John使用Fork的Jar包中的代碼
public void bar() {
   ...
   new Delegator().foo();
   ...
}

   OK,問題來了,大部分時候這段代碼也執行正常,可是某一天bar()忽然拋出NullPointerException,你最初挖的「坑」潛伏這麼久,終於有人掉進去了。John只能罵一句「好坑!」或者「Oh, shift!」了。那麼最初的getParameters()方法該怎麼寫纔好呢?很簡單,像下面這樣便可:

public String [] getParameters() {
    String [] result = new String[intParms.length];
    for(int n = 0; n < intParms.length; n++) {
        result[n] = "parameter " + intParms[n];
    }
    return result;
}

    如今若是intParms是一個空數組的話,返回的也是一個空數組。但若是intParms是null怎麼辦呢?很簡單,intParms顯然是類變量或者類成員,你只須要保證intParms始終不爲null便可,好比這樣:

private int[] intParms = new int[0];

    而後任何對intParms的修改都不能將其設爲null,但能夠把它重置爲空數組。這樣當前類內部的處理負擔可能加劇了,但其餘類的負擔卻大大減輕,別人也將更樂意使用你的代碼。

相關文章
相關標籤/搜索