函數(shù)設(shè)計PPT課件_第1頁
函數(shù)設(shè)計PPT課件_第2頁
函數(shù)設(shè)計PPT課件_第3頁
函數(shù)設(shè)計PPT課件_第4頁
函數(shù)設(shè)計PPT課件_第5頁
已閱讀5頁,還剩28頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、一個編寫的不好的函數(shù)Void HandleStuff(CORP_DATA* pInputRec, int CrntQtr, EMP_DATA EmpRec, float* pEstimRevenue, float YTDRevenue, int ScreenX, int ScreenY, COLOR_TYPE * pNewColor, COLOR_TYPE PrevColor, STATUS_TYPE* pStatus , int ExpenseType) int i;for( i = 1; irevenuei = 0;pInputRec-expensei = corpExpense Crnt

2、Qtri; UpdateCorpDatabase( EmpRec ) ;*pEstimRevenue = YTDRevenue * 4.0 /( float )CrntQtr);*pNewColor = PrevColor;*pStatus = Success;if( ExpenseType = 1) Profiti =Revenuei - Expense.Type1i; else if( ExpenseType = 2) Profiti = Revenuei - Expense.Type2i; else (if ExpenseType = 3) Profiti = Revenuei - Ex

3、pense.Type3i; 第1頁/共33頁上一個函數(shù)的缺點 函數(shù)的名字不好,不能說明函數(shù)是干什么的 函數(shù)進行了全局變量的讀寫操作。 CorpExpense、profit都是全局變量 函數(shù)的功能不是單一的。 它初始化了某些變量;對一個數(shù)據(jù)庫進行寫操作;又進行了某些計算工作。而這些功能之間又看不出任何聯(lián)系 函數(shù)中沒有采取預(yù)防非法數(shù)據(jù)的措施 如果CrntQtr的值為“0”,那么,表達式Y(jié)TDRevenue* 4.0real(CrntQtr)就會出現(xiàn)被零除的錯誤 指針沒有檢查是否為空 在函數(shù)中僅使用了CORP-DATA型參數(shù)的兩個域,卻傳入了整個結(jié)構(gòu)化變量 函數(shù)中的一些參數(shù)沒有使用過 :Screen

4、X和ScreenY 函數(shù)中的參數(shù)太多 函數(shù)中使用了幾個常數(shù)(神秘數(shù)字): 100,40,2和 3第2頁/共33頁函數(shù)設(shè)計的話題 函數(shù)設(shè)計概述 大原則 內(nèi)聚性 耦合性 信息隱藏 不好搞小動作 小細節(jié) 函數(shù)名 參數(shù) 返回值 函數(shù)內(nèi)部設(shè)計第3頁/共33頁函數(shù)設(shè)計概述系統(tǒng)設(shè)計模塊設(shè)計詳細設(shè)計編碼單體測試單體測試 函數(shù)設(shè)計主要在詳細設(shè)計中做第4頁/共33頁創(chuàng)建函數(shù)的理由(1) 降低復(fù)雜性 避免重復(fù)代碼段 限制改動帶來的影響 隱含順序 改進性能 實行集中控制 隱含數(shù)據(jù)結(jié)構(gòu) 隱含指針操作第5頁/共33頁創(chuàng)建函數(shù)的理由(2) 隱含全局變量 代碼段復(fù)用 計劃開發(fā)一個軟件族 改善某一代碼段的可讀性 改善可移植性

5、分隔復(fù)雜操作 獨立非標準語言函數(shù)的使用 簡化復(fù)雜的布爾測試 第6頁/共33頁大原則內(nèi)聚性 內(nèi)聚性是指一個函數(shù)內(nèi)的各種操作之間互相聯(lián)系的緊密程度 可以接受的內(nèi)聚性 功能內(nèi)聚性 順序內(nèi)聚性 通訊內(nèi)聚性 臨時內(nèi)聚性 不可接受的內(nèi)聚性 過程內(nèi)聚性 邏輯內(nèi)聚性 偶然內(nèi)聚性 函數(shù)設(shè)計的目標:強內(nèi)聚第7頁/共33頁可以接受的內(nèi)聚性 功能內(nèi)聚性 一個好的函數(shù)應(yīng)該具有功能內(nèi)聚性,即Do one thing and do it well 舉例:Sin(),GetCustomerName(),EraseFile()等 順序內(nèi)聚性 特點:函數(shù)內(nèi)的操作不能形成完整的功能,只是包含需要按特定順序進行的、逐步分享數(shù)據(jù)的一些

6、操作 舉例:下面五個操作完成一個功能:打開文件、讀文件、進行兩個計算、輸出結(jié)果、關(guān)閉文件。如果DoStep1()打開文件、讀文件和計算操作,而DoStep2()進行輸出結(jié)果和關(guān)閉文件操作。Dostep1和DoStep2只是把操作分隔開來,并沒有產(chǎn)生出獨立的功能,所以具有順序內(nèi)聚性第8頁/共33頁可以接受的內(nèi)聚性 通訊內(nèi)聚性 特點:函數(shù)中的兩個操作只是使用相同數(shù)據(jù),而沒有其它任何聯(lián)系 舉例:GetNameandChangePhoneNumber(),它取得的Name和PhoneNumber在同一個用戶記錄中,GetName和ChangePhoneNumber之間沒有其他的關(guān)系 臨時內(nèi)聚性 特點:

7、函數(shù)的幾個操作因為同時執(zhí)行才被放入同一個函數(shù) 例如:Startup(),CompleteNewEmployee(),Shutdown()等第9頁/共33頁不可接受的內(nèi)聚性 過程內(nèi)聚性 特點:函數(shù)中的操作是按某一特定順序進行的,卻不使用相同的數(shù)據(jù) 舉例:按一定的順序打印報告的函數(shù),打印的內(nèi)容包括銷售收入、開支、雇員電話表。給這個函數(shù)命名是非常困難的,模棱兩可的名字往往代表著某種警告 邏輯內(nèi)聚性 特點:函數(shù)的幾個操作之間沒有任何聯(lián)系,只是用傳進來的控制標志來決定執(zhí)行哪個操作,這些操作往往包括在一個很大的if“或者case語句中 舉例:函數(shù)InputAll()的輸入內(nèi)容可能是用戶名字、雇員時間卡信息

8、或者庫存數(shù)據(jù),至于到底是其中的哪一個,則由傳入函數(shù)的控制標志決定 偶然內(nèi)聚性 特點:同一個函數(shù)中的操作之間無任何聯(lián)系,也叫作“無內(nèi)聚性” 舉例:本文中開頭的那個不好的函數(shù)第10頁/共33頁內(nèi)聚性實例(1) 實例1:一個按給出的生日計算雇員年齡和退休時間的函數(shù)n分析:如果它是利用所計算的年齡來確定雇員將要退休的時間,那么它就具有順序內(nèi)聚性。而如果它是分別計算年齡和退休時間的,但使用相同生日數(shù)據(jù),那它就只具有通訊內(nèi)聚性。n如何改進成功能內(nèi)聚性呢?可以分別建立兩個函數(shù),一個根據(jù)生日計算年齡,另外一個根據(jù)生日確定退休時間,確定退休時間函數(shù)將調(diào)用計算年齡的函數(shù),這樣,它們就都是功能內(nèi)聚性的,而且其它函數(shù)

9、也可以調(diào)用其中任一個函數(shù),或這兩個都調(diào)用第11頁/共33頁內(nèi)聚性實例(2) 實例2:一個函數(shù)將打印季度開支報告、月份開支報告和日開支報告,具體打印哪一個,將由傳入的控制標志決定n如何改進程功能內(nèi)聚性呢?n建立三個函數(shù):一個打印季度報告,一個打印月報告、一個打印日報告,改進原來的子程序,讓它根據(jù)傳進去的控制標志來調(diào)用這三個函數(shù)之一。調(diào)用函數(shù)將只有調(diào)用代碼而沒有自己的計算代碼,因而具有功能內(nèi)聚性。而三個被調(diào)用的子程序也顯然是功能內(nèi)聚性的n分析 具有邏輯內(nèi)聚性第12頁/共33頁內(nèi)聚性實例(3) 實例3:一個函數(shù)先讀取雇員的名字,然后是地址,最后是它的電話號碼。這種順序是用戶要求的。另外一個函數(shù)將讀取

10、關(guān)于雇員的其它信息。n如何改進程功能內(nèi)聚性?把它分為幾個部分,并把這幾部分分別放入程序中。要保證調(diào)用程序的功能是單一、完善的。調(diào)用程序應(yīng)該是諸如GetEmployeeData()這樣的函數(shù),而不該是像GetFirstPartOfEmployeeData()這類的函數(shù)??赡苓€要改動其余讀取數(shù)據(jù)的子程序n分析 如何雇員信息放到一個記錄中,是順序內(nèi)聚;否則是過程內(nèi)聚性第13頁/共33頁內(nèi)聚性實例(4) 比如一個函數(shù)進行某種復(fù)雜計算的前5個操作,并把中間結(jié)果返回到調(diào)用函數(shù)。由于5項操作可能要用好幾個小時,因此當系統(tǒng)癱瘓時,函數(shù)要把中間結(jié)果存入一個文件中,函數(shù)還要檢查磁盤,以確定其是否有足夠空間來存儲最

11、后計算結(jié)果,并把磁盤狀態(tài)和中間結(jié)果返回到調(diào)用程序產(chǎn)生足夠數(shù)目的文件確定磁盤空間進行安全計算寫數(shù)據(jù)到文件進行前五步存儲中間結(jié)果進行最后一步n分析 原來的函數(shù)是由一系列令人莫名奇妙的操作組成的,與功能內(nèi)聚性相距甚遠n如何改進成功能內(nèi)聚性? 首先,調(diào)用程序應(yīng)該調(diào)用幾個獨立的函數(shù): 1)進行前5步計算; 2)把中間結(jié)果存入一個文件 ; 3)確定可用的磁盤存儲空間。如果調(diào)用函數(shù)叫ComputeExtravagantNumber(),那么它不應(yīng)該把中間結(jié)果寫入一個文件,也決不該為后來的操作檢查磁盤剩余空間,它所作的就僅限于計算一些數(shù)而已。改進這個設(shè)計,將至少影響到一到兩個層次上的程序, 對于這項任務(wù)的較好

12、設(shè)計,如下圖所示 第14頁/共33頁內(nèi)聚性總結(jié) 共享數(shù)據(jù)、各個操作都是為了完成函數(shù)的功能而存在功能內(nèi)聚 共享數(shù)據(jù)、各個操作順序進行順序內(nèi)聚 共享數(shù)據(jù)、各個操作之間沒有聯(lián)系通訊內(nèi)聚 不共享數(shù)據(jù)、各個操作同時進行臨時內(nèi)聚 不共享數(shù)據(jù)、根據(jù)控制標記決定做哪個操作邏輯內(nèi)聚 不共享數(shù)據(jù)、各個操作順序進行過程內(nèi)聚 不共享數(shù)據(jù)、操作之間沒有任何關(guān)系偶然內(nèi)聚第15頁/共33頁大原則耦合性 耦合性是指兩個函數(shù)之間聯(lián)系的緊密程度 函數(shù)與其它函數(shù)之間的聯(lián)系應(yīng)該是直接、可見、松散和靈活的,函數(shù)應(yīng)該容易被其他函數(shù)調(diào)用 函數(shù)對外的接口包括參數(shù)、函數(shù)中使用的全局變量和數(shù)據(jù)庫或文件等 耦合標準 耦合規(guī)模 兩個函數(shù)之間聯(lián)系的數(shù)

13、量越少越好:參數(shù)越少越好,使用的全局變量越少越好,使用數(shù)據(jù)庫和文件的范圍越少越好 密切性 兩個函數(shù)之間聯(lián)系越直接越好,使用參數(shù)最直接,其次是全局變量,最后的數(shù)據(jù)庫或文件 可見性 兩個函數(shù)之間聯(lián)系越顯著越好,使用參數(shù)可見性最強 靈活性 改變兩個函數(shù)之間聯(lián)系越容易越好第16頁/共33頁耦合層次 簡單數(shù)據(jù)耦合 兩個函數(shù)之間傳遞的數(shù)據(jù)是非結(jié)構(gòu)化的,并且全部都是通過參數(shù)表進行的 這通常稱作“正常耦合”,這也是一種最好的耦合 數(shù)據(jù)結(jié)構(gòu)耦合 兩個函數(shù)之間傳遞的數(shù)據(jù)是結(jié)構(gòu)化的,并且是通過參數(shù)表實現(xiàn)傳遞的 如果使用恰當?shù)脑挘@種耦合也不錯 控制耦合 一個函數(shù)通過傳入另一個函數(shù)的數(shù)據(jù)通知它該作什么 控制耦合是令人

14、不快的, 因為它往往與邏輯內(nèi)聚性聯(lián)在一起,并且,通常都要求調(diào)用者了解被調(diào)函數(shù)的內(nèi)容與結(jié)構(gòu) 全局數(shù)據(jù)耦合 兩個函數(shù)使用同一個全局數(shù)據(jù) 如果所使用的數(shù)據(jù)是只讀的,那么這種耦合還是可以忍受的,但是,總的來說,全局耦合是不受歡迎的第17頁/共33頁耦合的例子 Tan(float degree) 簡單數(shù)據(jù)耦合n一個函數(shù)向另一個函數(shù)傳遞姓名、住址、電話號碼、生日和身份證號碼等五個變量。 簡單數(shù)據(jù)耦合n一個函數(shù)向另一個函數(shù)傳遞變量EmpRec,EmpRec是一個結(jié)構(gòu)化的變量,包括姓名、住址、生日等等五個方面的數(shù)據(jù) 如果被調(diào)用的函數(shù)全部使用這五個域,那是可接受的數(shù)據(jù)結(jié)構(gòu)耦合 如果被調(diào)用的函數(shù)只使用其中兩個域,

15、比如電話號碼和生日。這雖然還是數(shù)據(jù)結(jié)構(gòu)耦合,但卻不是個很好的應(yīng)用 如果生日和電話號碼作為簡單變量來傳遞的話,將使聯(lián)系更加靈活,而且會使它們之間的兩個特定域真正聯(lián)系的可見性更好第18頁/共33頁耦合的例子 一個函數(shù)向另一個函數(shù)傳遞控制標志,通知它到底是打印月報表、季度報表還是年度報 控制耦合n一個函數(shù)以全局變量的方式改動一個表的入口,這個表是以雇員的識別卡作為索引的。然后,這個函數(shù)又調(diào)用另一個函數(shù)并把雇員識別卡作為一個參數(shù)傳遞給它,而這個被調(diào)用的函數(shù)則用雇員識別卡去讀全局數(shù)據(jù) 不可取的全局數(shù)據(jù)耦合n一個函數(shù)把雇員識別卡傳遞給另一個函數(shù),兩個函數(shù)都利用這個識別卡從一個全局表中讀取雇員的名字,兩個函

16、數(shù)都沒有改變?nèi)謹?shù)據(jù)。 可取的全局數(shù)據(jù)耦合第19頁/共33頁大原則封裝(信息隱藏) 封裝有兩層含義 為了隱藏一些信息,往往會形成一個或多個函數(shù) 函數(shù)的名字和參數(shù)應(yīng)該盡量少的暴露實現(xiàn)的細節(jié),這樣可以在不影響用戶的情況下方便的修改函數(shù)的實現(xiàn)方式 常見需要隱藏的信息 容易被改動的區(qū)域 對硬件有依賴的地方 輸入和輸出 非標準語言特性 難于設(shè)計和實現(xiàn)的域 狀態(tài)變量不要使用邏輯型變量作為狀態(tài)變量,應(yīng)使用枚舉型變量 使用存取子程序檢查變量,而不要對其直接檢查 數(shù)據(jù)規(guī)模限制 商業(yè)規(guī)則 預(yù)計得到的其他改動 復(fù)雜的數(shù)據(jù) 復(fù)雜的邏輯第20頁/共33頁大原則不要搞小動作 不要修改調(diào)用者的數(shù)據(jù)Struct Sample

17、int data1;int data2;Int Sum(Struct Sample* pInputRec)if( pInputRec-data1 data1 = 0; /這樣做不好return pInputRec-data1 + pInputRec-data2;Int Sum(Struct Sample* pInputRec)/ 修改成這樣就好多了int temp =pInputRec-data1 =0)? pInputRec-data1:0;return temp + pInputRec-data2;第21頁/共33頁大原則不要搞小動作 避免使用全局變量 全局變量的危害 全局數(shù)據(jù)的疏忽改變。

18、你可以會在某處改變?nèi)肿兞康闹担趧e處又會錯誤地以為它仍保持著原值TheAnswer = GetTheAnswer();TheAnswer是一個全局變量OtherAnswer = GetOtherAnswer();GetOtherAnswer 改變了TheAnswerAverageAnswer = (TheAnswer + OtherAnswer)/2AverageAnswer錯誤 伴隨全局變量的奇怪的別名問題 Void WriteGlobal (int& InputVar) GlobaIVar = lnputVar + 1; cout“input Varinble ”InputVa

19、r; cout“Global Varinble “next; / 直接使用全局變量Node = nextEmployee(node); / 比較抽象,容易理解 把對數(shù)據(jù)的所有存取保持在同一抽象水平上 AddEvent(Event) EventCount = EventCount-l / 和上一個語句的抽象程度不同第23頁/共33頁小細節(jié)函數(shù)名 函數(shù)名要有意義,要能描述函數(shù)所做的一切 在函數(shù)名字中,應(yīng)描述所有輸出結(jié)果及其附加結(jié)果 如果很難為一個函數(shù)命名,就需要考慮這個函數(shù)的功能是不是有問題 實現(xiàn)行為的過程或函數(shù)要使用動詞或動詞短語 如PrintReport(), CheckOrder() 如果函

20、數(shù)只有一個返回值,可以用返回值來描述 如Cos(), CurrentPenCount() 如果函數(shù)返回布爾值,可以在形容詞或名詞前加Is或Has,如IsPrinterReady(), HasFirstName() 命名約定 公開的接口函數(shù)和全局名字空間的函數(shù)選擇SmallTalk風(fēng)格的命名原則(一種首字母大寫,字間直接相連而無分隔符的書寫風(fēng)格),如IsPrinterReady() 私有的函數(shù)使用C+ 草擬標準工作底稿使用的約定(全部為小寫字符、字間以下劃線分隔),如is_printer_ready()第24頁/共33頁小細節(jié)參數(shù)(1) 函數(shù)的參數(shù)的命名要有意義stringCopy( char*

21、 str1, char* str2); /*這樣的參數(shù)命名不好,很難區(qū)分*/ 函數(shù)參數(shù)的順序要合理 按照輸入一修改一輸出的順序排列參數(shù),但是首先要符合使用習(xí)慣/*這個參數(shù)順序不符合使用習(xí)慣,很容易出錯*/StringCopy( char*strSource, char* strDestination)因為我們習(xí)慣這樣使用:stringCopy( str, “hello”) 如果幾個函數(shù)中使用了相似的參數(shù),應(yīng)使用相同的順序如strncpy和memncpy 把狀態(tài)和“錯誤”變量放在最后 參數(shù)的個數(shù)不要太多,盡量控制在7個以內(nèi) 如果參數(shù)太多,在使用時容易將參數(shù)類型和順序搞錯 參數(shù)太多,有時也意味著函

22、數(shù)功能劃分不好 使用所有的參數(shù),刪除沒有用到的參數(shù)第25頁/共33頁小細節(jié)參數(shù)(2) 對參數(shù)的限制越少越好,但是如果對參數(shù)的取值有限制,一定要加上注釋來說明 如果函數(shù)不是使用結(jié)構(gòu)化變量中的絕大部分,那么就只傳遞它所用得到的那一部分 結(jié)構(gòu)體如果很大,要用指針或引用傳遞 參數(shù)太大,占用的堆??臻g大,調(diào)用的效率也低 如果參數(shù)是指針,且僅作輸入用,則應(yīng)在類型前加const,以防止該指針在函數(shù)體內(nèi)被意外修改 第26頁/共33頁小細節(jié)返回值 顯式的聲明函數(shù)的返回值類型 原理:如果不顯示的聲明返回值類型,不同的編譯器可以給與不同的解釋 如: TestFunc()最好能顯示的聲明為int TestFunc(v

23、oid) 函數(shù)名字和返回值類型在語義上不可沖突 Int getChar()就是一個不好的設(shè)計 不要將正常值和錯誤標志混在一起返回。正常值用輸出參數(shù)獲得,而錯誤標志用return返回 有時候函數(shù)原本不需要返回值,但為了增加靈活性(如支持鏈式表達),可以附加返回值 例如 char *strcpy(char *strDest,const char *strSrc) 函數(shù)的每種出錯返回值的意義要清晰、明了、準確,防止使用者誤用、理解錯誤或忽視錯誤返回碼第27頁/共33頁小細節(jié)函數(shù)內(nèi)部設(shè)計 函數(shù)體的規(guī)模不要太大,否則難以理解。函數(shù)過大,也容易出錯 資源管理:誰申請誰釋放 除非函數(shù)的功能就是申請資源(如malloc, openfile等函數(shù)),否則盡量不要在函數(shù)內(nèi)部申請資源并返回資源的句炳或指針,如申請內(nèi)存返回內(nèi)存指針,打開文件返回文件指針等Void GetData( struct Sample *ppData); /不好Void GetData( struct Sample *pDat

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論