子程序設計原則


子程序(routines)是為實現一個特定功能而編寫的一個可被調用的方法(method)、函數(function)或過程(procedure)。如Java中的方法,C++里的函數。現代編程語言如Java、C++、VB、JavaScript、Ruby等都同時支持函數和過程。

一般認為函數指具有返回值的子程序,過程指沒有返回值的子程序。C++中把所有子程序成為函數,其實那些返回值為void的函數在語義上也是過程。函數與過程的區別更多是語義上的區別,而不是語法的區別。

語言純化論者認為一個函數應該只有一個返回值,這和數學函數一樣。即函數只接受輸入(參數),通過參數運算返回結果。 除此之外的效果被稱為函數的副作用,比如修改全局變量。

 

以JS示例

function sum1(x, y) {
    return x+y    
}
function sum2(x, y) {
    alert(x+y)    
}

sum1是一個函數,它有輸入並返回結果;sum2則是過程,接受輸入,處理輸入(打印輸出結果),但沒有返回結果。

 

好的子程序需要遵循以下原則

  • 高內聚
  • 好的命名
  • 長度適中
  • 合理的參數

 

一、高內聚性

內聚性是計算機科學里很重要的一個概念,由Larry Konstantin在1974年的一篇論文提出。它由分為以下

1. 功能內聚(Functional cohesion,最高

最好最強的一種內聚性,即一個子程序僅執行一個操作,有的書也稱“只做一件事,做好一件事”。這種子程序執行的操作與其名稱多數是相符的,如sum執行相加,deletePage刪除頁面。

2. 順序上的內聚(Sequential cohesion

指子程序內需按特定順序執行操作,這些步驟需要共享數據,且在全部執行后才完成子程序的完整功能。比如需要先計算A,再使用A計算B,接着取B計算C。

3. 通信上的內聚(Communicational cohesion

是指子程序不同操作使用了相同數據,但不存在任何聯系。

4. 臨時的內聚性(Temporal cohesion

是指含有一些因為需要同時執行才放到一起的操作的子程序。

5. 邏輯上的內聚性(Logical cohesion

是指若干操作被放入同一個程序中,通過傳入的控制標志選擇執行其中的一項操作。

6. 偶熱的內聚性(Coincidental cohesion 最低

指子程序中各個操作直接沒有可以看到的內聯,也稱為“無內聚性”或“混亂的內聚性”。

 

二、好的命名

好的命名能清晰的描述子程序所做的一切。以下是一些命名注意事項

1. 描述子程序所完成的功能

2. 避免使用無意義的、模擬或表達不清的詞

3. 不要僅通過數字來區分不同的子程序名

4. 根據需要確定子程序名字的長度

5. 對返回值要有所描述

6. 一般是動詞+名詞形式

7. 使用對仗詞,如add/remove, begin/end, first/last, get/put, up/down/, show/hide, open/close。

 

三、長度適中

“子程序/函數的第一要素就是短小,第二條規則還是短小”,鮑勃大叔如此說。理論上認為子程序的長度最大長度通常是一屏代碼,大約50-150行。

一項對子程序的研究發現,平均100-150行代碼的子程序需要修改的幾率最低(Lind and Vairavan 1989)。

 

IBM一項研究發現,最容易出錯的是那些超過500行代碼的子程序。超過500行后,子程序的出錯率和代碼行數成正比。在面向對象編程中,一大部分子程序都是訪問器子程序(getter),它們都非常短小。任何時候復雜算法總會導致較長的子程序,這種情況下允許長度增加到100到200行。

 

四、合理的參數

子程序之間的接口是程序中最易出錯的地方,Basili和Perrricone所做的一項研究發現程序中39%的錯誤都是屬於內部接口錯誤。也就是子程序間互相通信時所發生的錯誤。應該按以下原則處理

1. 按照輸入-修改-輸出的順序排列參數。不要隨機地按字母順序排列參數,而應先列出輸入參數,然后是即作為輸入又作為輸出的參數,最后是輸出的參數。比如Ada就要專門的關鍵字in,out。

procedure InvertMatrix {
    originalMatrix: in Matrix;
    resultMatrix: out Matrix;
}

 

2. 如果幾個子程序都用了類似的一些參數,應該讓這些參數的排列順序一致。

dom = {
    setWidth: function(elem, value) {
        // ...
    },

    setHeight: function(elem, value) {
        // ...
    }
}

 

3. 使用所有的參數,既然定義了該參數就應該使用它,如果不用它就應該刪掉它。

 

4. 把狀態或出錯的變量放在后面,狀態和那些用於指示發生錯誤的變量應放在參數表最后。它們只是程序的附屬功能且只用於輸出的參數。

 

5. 不要把子程序的參數用於工作變量

function process(inputVal) {
    inputVal = inputVal - 10;
    return inputVal  
}

這段JS代碼中,省略了一個變量聲明,inputVal很容易讓人誤解,即是輸入又是輸出,改為如下

function process(inputVal) {
    var outputVal = inputVal - 10;
    return outputVal  
}

  

6. 子程序的參數個數限制在7個以內。鮑勃大叔說的更極端 “最理想的參數數量是零,其次是單參數函數,再次是雙參數函數,應盡量避免三參數函數”。心理學研究發現,人類很難記住超過7個單位的信息。這一發現已應用在各個領域。  

 

相關:

Miller 神奇數字7

子程序(過程、函數、方法)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM