在閱讀《阿里巴巴Java開(kāi)發(fā)手冊(cè)》時(shí),發(fā)現(xiàn)有一條關(guān)于關(guān)于常量定義的規(guī)約,具體內(nèi)容如下:
圖中的反例是將數(shù)據(jù)緩存起來(lái),并使用魔法值加鏈路 id 組成 key,這就可能會(huì)出現(xiàn)其他開(kāi)發(fā)人員在復(fù)制粘貼的時(shí)候,少?gòu)?fù)制 _
的情況發(fā)生,這種錯(cuò)誤很難去檢查到,因?yàn)樽x取緩存不存在,可能會(huì)去數(shù)據(jù)庫(kù)讀取,很難察覺(jué)到。
如果在生產(chǎn)環(huán)境中,大量的請(qǐng)求進(jìn)來(lái),緩存全部失效,直接請(qǐng)求數(shù)據(jù)庫(kù),導(dǎo)致數(shù)據(jù)庫(kù)連接過(guò)多,查詢效率變低的問(wèn)題發(fā)生,因此看來(lái)魔法值確實(shí)應(yīng)該避免出現(xiàn)在代碼中。
另外在 《Clean Code》 和 《重構(gòu)》 等書中也提到了類似的問(wèn)題,在代碼中出現(xiàn)原始形態(tài)數(shù)字通常來(lái)說(shuō)是壞現(xiàn)象,應(yīng)該用命名良好的常量類隱藏它。
靜態(tài)常量取代魔法值
像下面這個(gè)例子:
if (billCount > 75) { //todo } else { //todo }
如果在不了解這塊的業(yè)務(wù)的同事,在讀到這塊代碼的時(shí)候,可能會(huì)想,75
是什么鬼,為啥和這個(gè)數(shù)比較,背后深藏著什么秘密嗎?可能只有當(dāng)時(shí)的開(kāi)發(fā)人員記得了,導(dǎo)致代碼可讀性和可維護(hù)性極差。
如果聲明一個(gè)常量,來(lái)替換該魔法值,可能就會(huì)使代碼的可讀性和可維護(hù)性大大增加。
static final Integer BASIC_BILL_COUNT = 75;
還有些魔法表達(dá)式,比如:
if (value > 60 && value <= 80 && type = 1) { // todo }
比如這個(gè)表達(dá)式是表示狀態(tài)為正常且項(xiàng)目活躍,就可以定義:
boolean isActiveProject = value > 60 && value <= 80 && type = 1;
這樣是不是可讀性就提高了,一眼就可以看出來(lái)這塊代碼的邏輯。
枚舉類取代魔法值
還有一種消除魔法值的方式是使用枚舉類代替,下面讓我們舉個(gè)例子:
if (eventId == 1) { System.out.println("睡覺(jué)"); } else if (eventId == 2) {
System.out.println("吃飯"); } else if (eventId == 3) { System.out.println("打豆豆");
}
如上代碼是針對(duì)事件 id 去執(zhí)行相應(yīng)的事件,如果事件比較少,大家還可以勉強(qiáng)記住每個(gè) eventId 對(duì)應(yīng)的含義,但是隨著事件 id
的增多,很可能會(huì)發(fā)生,新來(lái)的員工把事件 id 給搞混了,導(dǎo)致執(zhí)行錯(cuò)誤的事件,發(fā)生 bug。
那么我們可以使用枚舉類來(lái)表示相應(yīng)的事件:
public enum EventEnum { /** * 睡覺(jué) */ SLEEP_EVENT(1, "睡覺(jué)"), /** * 吃飯 */
EAT_EVENT(2, "吃飯"), /** * 打豆豆 */ FIGHT_PEA_EVENT(3, "打豆豆"); private int
eventId; private String desc; EventEnum(int eventId, String desc) {
this.eventId = eventId; this.desc = desc; } public int getEventId() { return
eventId; } public String getDesc() { return desc; } }
修改完之后的代碼如下:
if (eventId == EventEnum.SLEEP_EVENT.getEventId()) { System.out.println("睡覺(jué)");
} else if (eventId == EventEnum.EAT_EVENT.getEventId()) {
System.out.println("吃飯"); } else if (eventId ==
EventEnum.FIGHT_PEA_EVENT.getEventId()) { System.out.println("打豆豆"); }
是不是可讀性急劇提升,還不快看看自己代碼中有沒(méi)有這樣的魔法值出現(xiàn),有的話趕緊改造起來(lái)。
還有如果你需要在不同的地點(diǎn)引用同一數(shù)值,魔法數(shù)會(huì)讓你煩惱不已,因?yàn)橐坏┻@些數(shù)字發(fā)生改變,就必須在程序中找到所有的魔法值,并將它們?nèi)啃薷囊槐椋@樣就太費(fèi)時(shí)費(fèi)力了。
其實(shí)不只是 Java 不應(yīng)該在代碼中使用魔法值,其他語(yǔ)言亦是如此。
總結(jié)
本文主要介紹了為什么不允許在代碼中出現(xiàn)魔法值以及如何將代碼中已有的魔法值去除掉。
代碼可讀性還是比較重要的,你肯定不希望別人在接手你的代碼的時(shí)候,罵到這數(shù)字啥意思,這代碼寫得跟粑粑一樣。
最好的關(guān)系就是互相成就,大家的在看、轉(zhuǎn)發(fā)、留言三連就是我創(chuàng)作的最大動(dòng)力。
參考
《Java開(kāi)發(fā)手冊(cè)》泰山版
熱門工具 換一換
