(1/8)[代碼整潔之道]你真的會用枚舉嗎?非也!

▄︻┻┳═一Agenda:html

▄︻┻┳═一(1/8)[代碼整潔之道]你真的會用枚舉嗎?非也!java

▄︻┻┳═一(2/8)枚舉的錯誤用法 之 方法參數程序員

▄︻┻┳═一(3/8)枚舉的錯誤用法 之 方法參數(二)spring

▄︻┻┳═一(4/8)枚舉的錯誤用法 之 方法返回值數據庫

▄︻┻┳═一(5/8)枚舉的錯誤用法 之 方法體內部ide

▄︻┻┳═一(6/8)枚舉的錯誤用法 之 分支判斷post

▄︻┻┳═一(7/8)藉助枚舉說一下數據類型定義規範this

▄︻┻┳═一(8/8)RPC接口能用枚舉就請考慮枚舉編碼


 

 

【preface】

§1 url

《代碼整潔之道》裏提到」用異常代替返回錯誤碼「。若是缺少代碼維護經驗,估計一時理解不了其中含義。寫代碼是一回事,維護代碼是一回事。
用異常代替返回錯誤碼是對代碼「職責」的運用,即分離業務邏輯代碼和錯誤處理代碼。同時,用拋出異常的方式代替返回錯誤碼並未改變方法的返回值,對方法沒有產生任何破壞。

§2

我在小組的開發規範裏指明一條「嚴禁不加思考的代碼copy。當代碼copy超過10行,你必定要思考,是否是該重構了?」
也許有些同窗並不知道DRY原則,也不清楚「小規模複用」。 So,Just do it!照作便可,往後也許會懂。

 

【正確使用方式談】

若是變量值僅在一個範圍內變化,且帶有名稱以外的延伸屬性,則定義爲枚舉類。(《阿里巴巴Java開發手冊》中也有說起)

毋庸置疑,枚舉提升了代碼的可讀性和可維護性。

我給前面這句話加個定語——「正確使用」。就是說,正確使用枚舉能夠提升代碼的可讀性和可維護性。

若是使用不當,可能達不到效果,甚至拔苗助長。 

 

若是把某域定義成了枚舉,那麼,正確使用枚舉要注意以下幾點

  • 除了對外的輸入輸出,程序內部涉及到該域的,一概用枚舉類型。例如:方法參數、方法返回值、bo的屬性。
  • 接收到外來的數據後,在使用該域時,應先把該域轉換成枚舉類型。

說明一下,上面兩點提到的「外」指的是當前應用系統的外部,如db、其餘交易系統、http接口調用。

要作到上面兩點,容易,也不容易。 我見到不少的程序,都沒有正確使用枚舉。因此再也不一遍一遍重複講了,看這篇博客吧。下面以一例來闡釋。

 

【一例以明之】

簡單寫一個demo,目錄結構以下圖:

 

 

 

§1 各package的職責:common是通用的,這裏只定義了一個枚舉類CurrencyEnum;bo是程序裏用到的業務數據對象;po即持久化對象,對應數據庫裏的數據表;service是業務處理服務類。(參考PO/POJO/BO/DTO/VO的區別

 

§2 各class文件說明:

CurrencyEnum把「貨幣類型」這個域定義爲枚舉。

PayPO是持久化對象,數據類型只能用基本類型。咱們通常就是在讀寫庫時用它。其中,currency字段存儲的值是枚舉裏定義的CNY、USD、GBP、JPY、HKD。

PayBO是程序裏各class方法傳輸的對象。那麼它就不一樣於PayPO了。它頻繁穿梭在程序裏,因此咱們要能很容易就能識別出來它是最好的了(可讀性),這裏,就用到了上面定義的枚舉類型。

RouteService是模擬的一個獲取路由的服務類,爲了說的更明白,這裏使用方法重載定義了兩個方法,一個方法的參數是枚舉,一個方法的參數是bo。

用法見MainService。模擬了一個從db獲取對象,而後轉換成枚舉或bo獲取路由的過程。

 

§3 代碼:

 CurrencyEnum:

package enumdemo.common;


/**
 * 貨幣類型枚舉
 */
public enum CurrencyEnum {
    CNY("CNY", "人民幣"),
    USD("USD", "美圓"),
    GBP("GBP", "英鎊"),
    JPY("JPY", "日元"),
    HKD("HKD", "港元");

    //alphabet
    private final String alphabetCode;
    private final String name;

    CurrencyEnum(String alphabetCode, String name) {
        this.alphabetCode = alphabetCode;
        this.name = name;
    }

    public String getAlphabetCode() {
        return alphabetCode;
    }

    public String getName() {
        return name;
    }

    /**
     * 經過英文字母編碼獲取對應的貨幣類型</br>
     *
     * @param alphabetCode 英文字母貨幣
     * @return
     */
    public static CurrencyEnum getByAlphabetCode(String alphabetCode) {
        if (null == alphabetCode) {
            return null;
        }
        for (CurrencyEnum currencyEnum : values()) {
            if (currencyEnum.getAlphabetCode().equals(alphabetCode)) {
                return currencyEnum;
            }
        }
        return null;
    }

}
View Code

 

PayPO:

package enumdemo.po;

import java.math.BigDecimal;

public class PayPO {
    String orderNo;
    BigDecimal money;
    String currency;

    // getter/setter(略)
}
View Code

 

PayBO:

package enumdemo.bo;

import enumdemo.common.CurrencyEnum;
import java.math.BigDecimal;

public class PayBO {
    String orderNo;
    BigDecimal money;
    CurrencyEnum currency;

    // getter/setter(略)
}
View Code

 

RouteService:

package enumdemo.service;

import enumdemo.common.CurrencyEnum;
import enumdemo.bo.PayBO;
import enumdemo.bo.RouteBO;

public class RouteService {
    public RouteBO getRoute(CurrencyEnum currency) {
        switch (currency) {
            case CNY:
                RouteBO routeBO1 = new RouteBO();
                //邏輯代碼略
                return routeBO1;
            default:
                RouteBO routeBO2 = new RouteBO();
                //邏輯代碼略
                return routeBO2;
        }
    }

    public RouteBO getRoute(PayBO payBO) {
        RouteBO routeBO = new RouteBO();
        if (CurrencyEnum.CNY == payBO.getCurrency()) {
            //邏輯代碼略
            return routeBO;
        } else {
            //邏輯代碼略
            return routeBO;
        }
    }
}
View Code

 

MainService:

package enumdemo.service;

import enumdemo.common.CurrencyEnum;
import enumdemo.bo.PayBO;
import enumdemo.po.PayPO;
import enumdemo.bo.RouteBO;
import org.springframework.beans.factory.annotation.Autowired;

public class MainService {
    @Autowired
    RouteService routService;

    public void process() {
        final PayPO payRecord = null;//TODO:僞代碼,這裏是讀庫獲得的
        String alphabetCode = payRecord.getCurrency();
        CurrencyEnum currencyEnum = CurrencyEnum.getByAlphabetCode(alphabetCode);

        // ** 直接傳枚舉類型
        RouteBO routeBO = routService.getRoute(currencyEnum);

        PayBO payBO = new PayBO();
        payBO.setMoney(payRecord.getMoney());
        payBO.setCurrency(currencyEnum);
        // ** 傳bo
        RouteBO routeBO1 = routService.getRoute(payBO);
    }
}
View Code

 

 

【conclusion】

上面示例裏PayBO的枚舉類型屬性 和 RouteService方法的枚舉類型參數或bo參數,使得枚舉的使用和判斷變得一目瞭然! 若是這裏把貨幣類型currency變量定義成String,那麼,你能夠比較與定義成CurrencyEnum的不一樣。一樣,PayBO裏的currency也如是。

有同窗該反問,這有什麼呀!你們記住貨幣類型有CNY、USD、GBP、JPY、HKD那幾個值不就好了。 那麼問題來了,咱們作的一個項目,可不是這個demo這麼簡單喲~,會有好多好多這樣的域,如訂單狀態,支付方式,產品類型,用戶類型,營銷方式。。。。。。,這些域的各個項的code多是0、一、二、三、四、五、六、七、8等這樣的數字(程序員對這些code的定義每每比較隨意,即便不隨意,受限於英語水平或拼音水平,定義出來的也每每不容易記憶),服務邏輯也遠比這個demo要複雜。你若是能記得住,舅服你。不過,你記得住,並不表明全部人都記得住。要知道,你不是一我的在做戰,你的項目也不是孤立的。

相關文章
相關標籤/搜索