很久以前我就考慮這樣乙個問題:有這樣乙個函式,它的功能是從乙個整數集合中返回最大的那個數,如何設計這個函式的簽名了?當時沒有得出令自己滿意的答案,所以就擱淺了。今天重新思考,終於有所悟!現在把我思索的整個過程展現於此。
最直觀的函式簽名設計如下:
getmaxelement(arraylistelelist);
乍看之下,很好,很直接的反映了意圖。稍微深入一點就發現,如果elelist為null或者其中元素個數為0,getmaxelement返回什麼了?第一反應,修改簽名為下面的形式:
getmaxelement(arraylistelelist,
outint
result);
我問了很多程式設計師,幾乎都是這樣處理的。我覺得這樣設計函式很彆扭,我喜歡直觀簡單的解決方案,無疑我最喜歡第一種簽名形式,它很好的反應的函式的意圖。而第二種了,它的設計不夠好,除了不夠直觀外,還有什麼更重要的缺陷?今天我知道了答案。
首先,我們想想看,當elelist為null或者其中元素個數為0時,getmaxelement知道怎麼處理這件事嗎?當然,不知道!因為在此函式中所有相關的上下文已經丟失了,那麼誰知道處理的方法了?對,是呼叫getmaxelement的呼叫方。呼叫方在呼叫getmaxelement之前就應該檢查elelist 是否滿足條件。那麼,這個條件是在**定義的了,目前的解決方案是在getmaxelement函式說明文件中。
呼叫方這麼做:
=if((elelist
==null)||
(elelist.count==0
))intmax
=getmaxelement(elelist);
由於呼叫方知道怎麼處理elelist為空和個數為0的錯誤的上下文,所以它很容易解決這個問題。如果採用第二種簽名,有何缺陷了?在第二種簽名情況下,呼叫方通常這麼做:
=intmax=0
;bool
succeed
=getmaxelement(elelist,
outmax);
if(!succeed)
到if(!succeed)語句時,呼叫方已經不知道getmaxelement返回的錯誤是不是由elelist為空和個數為0引發的,錯誤的根源丟失了,所以呼叫方對返回的false真是愛莫能助、唯有嘆息了!
到這裡,我總結了乙個設計原則:
不要讓錯誤傳播,在錯誤出現的發源地(萌芽期)就解決它!錯誤越是傳播到最後,關於處理它的上下文就丟失得越多,對於錯誤的蔓延就越是愛莫能助!
為getmaxelement方法加上注釋後是這個樣子:
//呼叫此函式前請確保elelist不為null,且其中元素個數大於0
intgetmaxelement(arraylistelelist);
這實際上是限制了乙個前置條件,關於前置條件和後置條件的更多資料可參考「契約式設計」!講到這裡,我考慮在.net平台上實現乙個契約設施dbc.net,該設施將在執行時自動檢測前置條件、後置條件等。很有可能像下面的樣子:
[precondition(elelist
!=null
)][precondition(elelist.count
>0)]
intgetmaxelement(arraylistelelist);
對於實現dbc.net有什麼好的建議,歡迎和我討論。我已經在申請了dbc.net的專欄歡迎你的加入!
函式設計之美 再談函式需要返回錯誤碼嗎?
zhuweisky在文章函式設計之美 函式需要返回錯誤碼 一 中總結 不要讓錯誤傳播,在錯誤出現的發源地 萌芽期 就解決它!錯誤越是傳播到最後,關於處理它的上下文就丟失得越多,對於錯誤的蔓延就越是愛莫能助!同意他的結論,我們知道在物件導向中單一職責是很重要的理念。函式在設計時也要秉承這個理念,保證函...
錯誤處理之函式返回值OR異常處理
問題 1 錯誤處理的方法有哪些?2 使用函式返回值還是丟擲異常?3 php 原框架下的異常處理機制是怎樣的?4 php yii框架下的錯誤處理方案是怎樣的?有什麼參考意義?如上所述四種處理方法,成員變數的方式多數使用在處理結果不用立即返回的情況,譬如對多個資料字段進行校驗返回校驗結果,使用場景比較明...
Oracle Oracle之Chr函式返回
chr函式 返回 返回 string,其中包含有與指定的字元 相關的字元。chr 0 為0的字元 chr 1 chr 2 chr 3 chr 4 chr 5 chr 6 chr 7 響鈴 chr 8 回格 chr 9 tab 水平製表符 chr 10 換行 chr 11 tab 垂直製表符 chr ...