編寫高質量代碼的思考

編寫高質量代碼的思考

前言

最近在看《代碼大全》,可以說是一本軟件開發的百科全書,特別厚,但是乾貨也很多。平時寫代碼,代碼規範是一個最低的要求(很多老代碼連最低要求都達不到),為什麼要這樣規定代碼要這麼寫,而不是那麼寫?這是一個值得深究的問題。而不是說我照著代碼規範寫代碼就算完了,高質量的代碼是一個專業工程師的追求。要知其然知其所以然,最近寫發票解析的代碼,因為涉及帶解析PDF的算法,複雜度比較高,所以花了很多時間在重構,學以致用的時候積累了一些心得。

信息隱藏原則

信息隱藏是面向對象設計的一個原則,是對封裝和模塊化的一個更高維度的概括。從Java的整個訪問限制設計就體現了信息隱藏的原則,各種訪問修飾符:public,protect,private,在類設計的時候,我們就要決定什麼暴露給外部,什麼隱藏起來。

舉一個例子下面的代碼表示一個有自增ID的Person類。

public class Person {

int id;

private static int G_MAX_ID = 0;

public Person() {

this.id = ++G_MAX_ID;

}

}

上面的類設計有什麼問題呢?它違反了信息隱藏的原則,直接將ID分配的方式暴露了,這會給後面的維護帶來很多問題:當你想給id的範圍做出限制的時候怎麼辦?當你在所有代碼中使用++G_MAX_ID分配ID時突然需要修改ID分配的算法怎麼辦?是不是需要去改所有++G_MAX_ID出現的地方?更好的設計是將ID的分配算法隱藏起來。

public class Person {

int id;

private static int G_MAX_ID = 0;

public Person() {

this.id = NewId();

}

private int NewId() {

return ++G_MAX_ID;

}

}

咋一看只是將++G_MAX_ID寫到一個方法裡面而已,但是它隱藏了ID分配的算法,讓調用者不需要關心裡面的實現,同時控制了變化,不管ID分配算法怎麼變,都不會影響其他的代碼。調用者瞭解的信息越多,受到的影響就越大,信息隱藏可以降低複雜度,控制變化的範圍。

上面的例子只是信息隱藏的一個簡單應用,下面我們來舉幾個其他的應用例子:

  • 為什麼不推薦使用魔法值(即未經定義的常量)?:這個明顯違反了信息隱藏的原則,當你將字面量直接寫在代碼裡面時,就將信息直接暴露了,後面需要修改的時候,一旦少改了某個地方的字面量,bug就出現了。
  • 循環依賴(即A調用B,B調用A的情況):類或方法之間的循環依賴會破壞信息隱藏,一個很直接的影響就是在測試的時候,A,B都需要同時準備好才能進行測試,而無法mock任意一方。
  • 使用全局變量:這個就不用說了,所有人都可以訪問你的時候信息就暴露無疑了,全局變量能不用就不用。
  • 考慮性能損失:有時候我們為了一些性能上的考慮就破壞信息隱藏原則,將一些變量全局化,這樣性能提高得不多,維護成本卻上升不少,完全是得不償失。

最後總結一下信息隱藏的好處:

  • 隱藏信息即隱藏了複雜度,降低了編程的負擔。
  • 隱藏信息即隱藏了底層變化,以便於在局部控制變化。

一些不太常見的編程技巧

函數(function)與過程(procedure)的選擇

我們先來看看函數與過程區別:

  • Function:有返回值的方法
  • Procedure:沒有返回值的方法

平時我們編程其實沒有太區別函數與過程,什麼時候用函數,什麼時候用過程其實沒有過多的考慮,感覺都可以用。一個選擇的規則就是當你的方法的目的是想返回跟你方法名稱相符的值的時候用函數,否則用過程

舉個例子,我看過很多XXProcessor接口裡面的方法都是XX process(),嚴格來講,這樣的命名是不符合上面的規則的,process是一個沒有含義的命名,但是卻有返回值,如果沒有返回值那它的命名才是合理的。

當然了,上面的規則僅供參考,世事無絕對,具體情況具體分析,當你不清楚用函數還是用過程的時候,可以參考這個規則。

使用boolean值來給程序做註釋

相信大家看到一個if語句有很多條件的時候都會特別頭痛,因為很難理解。例如下面的例子:

if ( ( elementIndex < 0 ) || ( MAX_ELEMENTS < elementIndex ) || elementIndex == lastElementIndex) {

do....

}

但如果換成下面的寫法,用boolean值的名字來給if語句註釋,看起來就很好理解了。

finished = ( ( elementIndex < 0 ) || ( MAX_ELEMENTS < elementIndex ) );

repeatedEntry = ( elementIndex == lastElementIndex );

if ( finished || repeatedEntry ) {

...

}

總結

怎麼寫高質量的代碼是一個很大的話題,這裡只是拋磚引玉,其實面向對象設計的很多原則都能夠給我們寫代碼的時候提供指導,寫代碼的時候要時刻記得學以致用,而不是敷衍了事,專業的軟件工程師必然要能寫得一手好代碼。


分享到:


相關文章: