回覆列表
-
1 # 使用者9857802307620
-
2 # 指尖時
可讀性: 個人覺得這個尤其重要, 你的變數名, 方法名能不能讓人見名知義. 命名是否統一, 不散漫.
可擴充套件性: 可擴充套件的程式的生命力才是強大的, 高質量的程式碼必須具有高可擴充套件性的特點. php本身就是可以被擴充套件的, 擴充套件性非常好, 非常方便, 這個是眾所周知的. 最好的編輯器vim也是擁有無敵的擴充套件性.
安全性: 這個重要性不言而喻, 沒有安全, 再優雅的程式碼也沒有任何意義.
耦合度: 程式的邏輯不應過分耦合, 使得牽一髮而動全身. 低耦合度可以使得程式碼的可重用性非常高.
執行效率: 天下武功, 唯快不破. 一個優秀的演算法可以讓程式的執行效率快幾個數量級. 資料結構+演算法=程式在今天依然不是一句空話.
一以貫之的命名原則:
如fetch,get,retrieve 都可以用作獲取,拿到 的意思,但是我們要根據實際的應用場景,在通一個類或者模組中儘量只使用其中一個作為方法名的字首,如getXXX
一詞一意原則:
如add表示增加,可以在任何地方增加,如前面,中間,後面等等。但是如果有一個方法需要表示只能在末尾附加,此時就不應該使用add方法了,而應該用append方法,這個原則給一以貫之命名原則做了限定,即只有是代表同樣的操作的時候才一以貫之。
使用解決方案領域名稱:
儘量使用專業的領域名稱
使用源自所涉問題領域的名稱:
當程式設計師很難在現有程式碼中使用專業領域名稱的時候,可以考慮使用源自所涉問題領域的名稱,可以理解為業務,瞭解業務,對於命名也是非常有幫助。
其實好的程式設計師和軟體設計師,所做的工作就是分離好解決方案領域和問題領域的概念,使得程式碼更加貼近於問題領域
好的函式命名---只做一件事
如果一個函數里面,包含了同一個抽象層級的多個函式,這樣也是算只做一件事,但是如果包含了不同抽象層級的,那就是做了很多事,多年的編碼經驗告訴我們,函式只做一件事,比做很多事好維護的多!
如何保證函式只做一件事
首先是這樣的,把做的事情進行分解,比如說 可以這樣來進行分解:
要做一個到大功能x ,就要先做第一個中等功能xx,要做一箇中等功能xx就得先做一個小功能xxx。然後做第二個中等功能yy,要做中等功能yy,就要先做小功能yyy........透過一層層分解,就能保證函式只做一件事了。
函式的引數儘量少
函式的引數和函式名不是一個抽象層級上的東西,會讓別人閱讀的時候感覺有點困難,在一個函式中儘量不要使用引數,或者只有一個引數,要是3個以上的引數,那確實有點多了,除非特別必要,不然真的不要寫那麼多引數,太多了 讓人容易誤解。還有一個非常值得注意的是不要使用引數作為返回值!!!一定要使用函式返回值,不然真的讓人很難讀懂你的程式碼!
一元函式的普遍形式
向函式傳入單個引數,有兩種普遍理由,第一種,如boolean fileExists(“myFile”),這種是判斷輸入引數 是什麼,怎麼了,等等。。第二種,如InputStream fileOpen(“myFile”),這種是把引數轉換為某種其他的東西,再輸出來! 這個是書寫一元函式普遍需要遵循的原則,值得注意的是,如果函式需要對輸入函式進行轉換的時候,轉換結果應該體現在函式的返回值上,而不是引數
函式的引數裡面不要放標識引數(即boolean)
因為函數里面放了標識引數,那麼該函式做的事情就不是一件事了,它必須要判斷當標識引數是真的時候,該做xxx,當標識引數為false的時候,該做yyy,在這種情況下,由於它要做很多的事,所以很難給她命名!例如這個函式 render(boolean isSuit); 當讀者看到呼叫該函式的程式碼時,render(true) 根本不知道這是幹嘛的!正確的做法是應該把他們拆開成兩個函式,如 renderForSuit() 和 renderForNoSuit() 這樣 就一目瞭然。一個小經驗,當給一個類或者函式,變數命名時感覺非常困難的時候,往往意味著我們分析,劃分的模組有問題,粒度不夠小,模組和模組,函式和函式之間有 很大的耦合,還需要我們再仔細分析,劃分,設計!
引數物件的抽取
如果一個函式擁有兩個及以上的引數時,往往可以意味著,其中的一些引數可以封裝成物件了,因為這些引數是一起傳遞到函數里面的,所以有很大的可能性,這些引數本身就有關係,所以把他們封裝成物件就是很自然的做法了!例如:
MakeCircle(int x,int y,int radius);
可以改造成
MakeCircle(Point point , int radius);
這樣就把x,y封裝到一個物件去了,對程式碼的可讀性有所提升!
函式命名--動詞與關鍵字
較好的函式命名可以讓使用我們程式碼的人很容易理解我們的程式碼,對於一元函式,應該使用動詞+關鍵詞(應該是名詞)的組合形式,如 write(name)這個函式,相當令人認同,但是如果使用writeField(name)也許會更好,即動詞+關鍵詞的組合。再比如 assertEqual(expected,actual) 這個方法,改成assertExpectedEqualActual(expected,actual)也許會更好,這樣別人再使用我的程式碼的時候就不用記住引數順序啦!(不過我對此表示懷疑,因為現代的IDE是可以提示函式引數的,所以為了讓函式名體現引數而寫這麼長的函式名,恐怕有點得不償失,並且引數函式名+裡面的引數已經體現了這個函式的意圖,所以看起來也比較容易讀!這個暫時放一邊吧,沒準以後再讀的時候就不一樣了)
函式不應該有副作用
例如一個函式
這個函式雖然名為checkPassWord ,意思是檢查使用者的密碼,實則它不只是幹了這麼一件事,它還幹了一件事是重新初始化Session,這顯然是不可以的,因為當別人接手你的程式碼的時候,要是相信了你這個函式的命名,認為它只是檢查密碼而已,不知道這背後的還有一個副作用是重新初始化Session,那麼就有可能丟失Session資料,這肯定是不可以接受的,所以 正確的做法應該是把這個副作用提出去,如果確實要重新初始化Session,那就老老實實搞在這個函式後面寫就是了!
分隔指令與詢問
函式要麼做什麼事,要麼回答是什麼事,二者不可兼得,要是兩個都做往往會做的很混亂
如下面這些語句
這個 乍一看,還真不太清楚想表達什麼? 這個set函式返回值代表什麼?是代表判斷設定屬性username成功與否的標識?還是判斷username 之前的值是否是zrc的標識呢?
不清楚,
更好的做法是如下:
這樣就一目瞭然了!
使用異常代替返回錯誤碼
如下程式碼:
使用錯誤碼返回 會導致程式碼裡面充滿著if else 的判斷。不利於程式碼的閱讀
正確的做法是 使用異常來處理這些
如下程式碼:
這樣的程式碼就把錯誤的處理資訊從程式碼的主路徑中抽離出來,更加容易閱讀!
錯誤處理只是一件事,抽離出try/catch程式碼塊
如函式:
經過這樣的抽離之後,就可以看出 程式碼寫的很優雅了!相當於delete函式只幹一件事,就是判斷是否有異常
最後再說一下,寫程式碼其實跟寫其他東西是一樣的,就像寫文章一樣,你先想什麼就寫什麼,然後再打磨它,初稿可能粗陋無序,那你就仔細斟酌,直到達到你心中的樣子。
一開始亂很正常,但是要在後續不斷的斟酌,思考,重構出你想要的樣子,寫程式碼不是一開始就按照規則來的,我想應該沒人能做到,只有不斷地寫,不斷地發現重複,不斷打磨重構才能寫出好的程式碼!