C語言的設計模式-單一職責


單一職責原則:

通常的定義是只專注於做一件事和僅有一個引起它變化的原因。對於接口、實現、函數級別往往我們比較容易關注單一職責,大家談的也比較多,但對於返回值、參數可能不會有太多的人關注。但往往就是這些不符合單一職責原則的設計可能導致一些很難發現的BUG。看看下面這段代碼:

pBuf = (byte*)realloc( pBuf, size);
if( pbBuf != NULL )
{
       TODO...
}

可能很多人一眼看上去並沒有什么問題,先讓我們看看這個庫函數的定義:

函數簡介
  原型:extern void *realloc(void *mem_address, unsigned int newsize);
  語法:指針名=(數據類型*)realloc(要改變內存大小的指針名,新的大小)。
  功能:先判斷當前的指針是否有足夠的連續空間,如果有,擴大mem_address指向的地址,並且將mem_address返回,如果空間不夠,
先按照newsize指定的大小分配空間,將原有數據從頭到尾拷貝到新分配的內存區域,而后釋放原來mem_address所指內存區域,同時
返回新分配的內存區域的首地址。即重新分配存儲器塊的地址。   返回值:如果重新分配成功則返回指向被分配內存的指針,否則返回空指針NULL。 

正常情況下pBuf是新空間的地址沒有任何問題,但我們考慮下如果分配失敗了呢,pBuf會被賦值成NULL,pBuf原指向的地址空間就沒有指針指向了,造成了內存泄露。這種問題往往很難定位。熟悉realloc機制的人可能對這個問題很不屑,認為高手不會犯這些錯誤。但我們可以想下有沒有辦法設計一個好的接口讓菜鳥也寫出不會出錯的代碼呢。假設這個庫函數的接口是這樣的呢:

函數簡介
  原型:extern flag realloc(void **ppMem_address, unsigned int newsize);
  語法:返回值 =(數據類型*)realloc(要改變內存大小的指針名,新的大小)。
  返回值:如果重新分配成功則返回指True(ppMem_address保存新分配空間地址),否則返回False(ppMem_address保存老空間地址)

相信任何一個使用這個接口的人都會寫出下面的代碼:

if( True == realloc( &pBuf, size))
{
       TODO...
}else
{
    TODO...
}

為什么有人會犯pBuf = (byte*)realloc( pBuf, size);這種錯誤?因為他只關注了realloc返回值是一個地址,沒有關注該返回值還有錯誤識別的功能,換句話來說這個庫函數的返回值不具備單一職責,導致了可能的錯誤使用。如果使用改進后的接口,因為返回值只有一個判斷分配成功與否的功能,相信沒有人還會用錯。

我們再仔細看看我們新的接口,總覺得似乎有什么地方還是不對,看到void **ppMem_address可能要想一下明白,這個參數既是入參又是出參,它承擔了原始地址的輸入和新地址的輸出,這不又違反了單一職責嗎?好吧我們再改進一下:

函數簡介
  原型:extern flag realloc(void *pIn_Mem_address,void **ppOut_Mem_address, unsigned int newsize);
  語法:返回值 =(數據類型*)realloc(要改變內存大小的指針名,新的內存指針名,新的大小)。
  返回值:如果重新分配成功則返回指True,否則返回False。

現在這個接口就算一個初次看到的人也應該大概知道什么意思,相信也不會寫出什么帶BUG的代碼,因為函數的參數、返回值都具有單一的功能,通過返回值來判斷分配成功與否,通過出參來獲取地址。一切看起來都很清晰。

在C庫中還有很多類似的函數,如果當初的設計人員能多考慮單一職責,也許現在的系統中就會少了很多隱藏的BUG,接口永遠是給別人使用的,一定要把使用者當成傻瓜,也許才能設計出好的接口。

轉載請注明原始出處:http://www.cnblogs.com/chencheng/archive/2012/12/11/2813688.html


免責聲明!

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



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