中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

診斷Java代碼:設(shè)計輕松的代碼維護

2018-06-11    來源:

容器云強勢上線!快速搭建集群,上萬Linux鏡像隨意使用

  有效調(diào)試源自良好的編程。設(shè)計易于維護的程序是程序員面臨的最困難挑戰(zhàn)之一,其部分原因在于程序通常并不是由那些編寫代碼的程序員維護的。為了有效維護這樣的程序,新程序員必須能夠快速了解程序的工作原理,如果程序員能夠單獨理解整個程序中各個小部分,那么就可以容易地了解程序的工作原理。

??通過討論可變性、可譯碼性、私有方法、最終方法、最終類、本地代碼、單元測試以及重構(gòu)問題,我們將簡述編寫程序的一些方法,以幫助使程序更易理解和維護。

??可變性和可譯碼性
??首先討論可變性問題。如果在一個程序的計算期間,其每一部分所處理的數(shù)據(jù)都沒有被該程序的其它、遠程部分更改,那么就很容易單獨理解該程序的各個部分。

??太多信息
??例如,請考慮一個使用容器類實例的程序,可以修改其中的成分鏈接。每次將容器從程序某一部分上的方法傳遞到該程序其它部分的方法,以及每次調(diào)用 new 表達式(其中容器被作為參數(shù)傳遞)時,容器就可能脫離調(diào)用方法的控制發(fā)生改變。

??在我們首先理解調(diào)用方法調(diào)用的每個方法如何修改容器之前,我們不能真正確保我們理解了調(diào)用方法,由此我們診斷錯誤的能力也就更差。如果這些被調(diào)用的每個方法都依次調(diào)用其它修改方法,那么維護程序員為了理解單個方法必須閱讀的代碼總量會迅速增加,多得無法控制。

??由于這個原因,對可變?nèi)萜骱筒豢勺內(nèi)萜魇褂貌煌悤浅S欣。在不可變版本中,容器的字段可以標記?final。

??求助于函數(shù)樣式
??相對于修改舊數(shù)據(jù),為構(gòu)造新數(shù)據(jù)而進行代碼編寫稱為函數(shù)樣式,因為程序的方法與數(shù)學函數(shù)相似,其行為是根據(jù)每個輸入所返回的輸出來單獨描述的。

??函數(shù)樣式經(jīng)常被忽略的優(yōu)點是相當容易單獨理解程序的個別組件。如果方法所操縱的數(shù)據(jù)決不會被其主體中執(zhí)行的任何操作改變,那么程序員要理解該方法必須做的就是理解那些操作返回的結(jié)果。將之與前面的一個方法調(diào)用幾個其它方法的方案相對照,那個方案中的其它幾個方法都修改這一方法所操作的數(shù)據(jù)結(jié)構(gòu)。

??Java 語言的一個相當好的特性是它允許我們使用 final 關(guān)鍵字(作為類型檢查器的偽指令)來聲明何時我們要使某個數(shù)據(jù)成為不可變。

??使用 final 關(guān)鍵字來避免變化是“釘住”類的方法行為的一個好方法。每次修改字段時,都有可能改變引用該字段的方法的行為。另外,將字段標記為 final 讓閱讀程序的其他程序員立即知道:不管整個程序有多大,決不要修改該字段。例如,請考慮下列表示不可變列表的類層次結(jié)構(gòu)。

清單 1. 表示不可變列表的類層次結(jié)構(gòu)

abstract class List {...}
class Empty extends List {...}
class Cons extends List {
private final Object first;
private final List rest;
}

??這些類中的所有字段都被標記成 final。要確保這些類的實例不可變,這樣做夠了嗎?不太夠。當然,即使字段被標記成 final,該字段本身的組件可能不是 final,記住這一點很重要。當那些組件更改時,引用那些組件的程序的任何部分可能會被修改,而不管字段本身是否改變。在上面的示例中,盡管列表的組成元素不能被修改,但是我們必須檢查那些元素本身沒有包含可能被修改的非最終字段。

??在這種情形中,盡管列表可能包含可變元素,但是我們可以看到存儲在給定列表中的元素序列由于以下原因而不可變:Empty 列表(即,長度為零的列表)的實例根本不包含任何元素;因此不能修改它們。Cons(非空列表)實例包含兩個字段,都是 final。第一個字段包含該列表的第一個元素,它不能被修改;第二個字段包含一個列表,其中包含所有剩余元素。如果這個列表的內(nèi)容不可變,那么該包含列表也不可變。

??但是包含在這第二個字段中的列表比包含列表的長度小一,所以如果我們知道長度為 n 的所有列表都不可變,那么我們就知道長度為 n + 1 的列表也不可變。因為我們已經(jīng)知道長度為零的列表不可變,所以我們也知道長度為 1、2、3 等的列表同樣不可變。

??跟蹤與此類似的數(shù)據(jù)結(jié)構(gòu)連接會很乏味,但當您能確定這種結(jié)構(gòu)的全局特性(諸如不可變性)時,這樣做是值得的。

??控制變化
??防止出現(xiàn)不期望的變化的最佳策略就是盡可能避免所有變化。只有當出現(xiàn)一定要改變的原因時(例如,當這樣做大大簡化了代碼結(jié)構(gòu)時),我們才應(yīng)該使用它。當可以避免變化時,所產(chǎn)生的好處是巨大的(在較低的維護費用和增強的健壯性方面)。

??即使存在一定要改變數(shù)據(jù)的原因,最好還是設(shè)法控制那種變化,從而盡可能限制可能產(chǎn)生的破壞。迭代器和流是數(shù)據(jù)結(jié)構(gòu)的極佳示例,這些數(shù)據(jù)結(jié)構(gòu)明確設(shè)計成通過允許我們以常規(guī)的、定義良好的形式利用一系列元素,而不是明確修改這些元素的某個句柄來控制變化。

??私有方法
??就如同將字段設(shè)置成 final 有助于限制對字段值產(chǎn)生外部影響一樣,將它們設(shè)置成 private 有助于限制它們對程序其它部分產(chǎn)生的影響。如果字段是私有的,那么我們可以確信該程序的其它部分都不與它直接相關(guān)。如果我們除去了該字段,并替換了該類數(shù)據(jù)的內(nèi)部表示,那么我們只要關(guān)心修正該類內(nèi)部的方法,以正確訪問新數(shù)據(jù)。

??在前面的示例中,請注意類 Cons 的字段是私有的。這樣的話,我們就可以通過讀方法(getter)及類似方法來控制如何訪問那些元素。如果我們列表的未來維護人員有時想要修改列表的內(nèi)部表示(例如,可以論證在某些平臺上,基于數(shù)組的列表或許更有效),那么程序員可以這樣做,而不必修改或甚至查看那些列表的任何客戶機。他只要重寫 getter 就可以對新數(shù)據(jù)采取適當?shù)牟僮鳌?/P>

??最終方法、最終類和理解本地代碼
??與將字段標記成 final 形成對比的是,將方法標記成 final 通常被指責為與 OO 設(shè)計目標不一致,因為這樣禁止繼承多態(tài)性。但是在嘗試理解大型程序的行為時,這樣有助于了解什么方法沒有被重寫。

??現(xiàn)在良好的 OO 設(shè)計涉及使用大量繼承,這的確是事實。事實上,繼承是許多 OO 設(shè)計模式的核心。但是那并不意味著我們應(yīng)該允許我們編寫的每個方法都被重寫。通常程序?qū)㈦[式地依賴某些沒有被重寫的關(guān)鍵方法。通過將這樣的方法標記成 final,我們將允許其他程序員更好地理解調(diào)用該方法的表達式行為。

??另外,將類標記成 final 會極大提高可譯碼性。它會真正有助于初步了解程序中哪些類決不會被子類化。事實上,我認為:只有不應(yīng)被標記成 final 的類才是程序中真正被子類化的類,以及那些有意從外部組件上被子類化的類(作為程序設(shè)計的固有部分)。

??有人可能認為這個概念會束縛將來的代碼維護人員,使他們不能擴展代碼。我認為這肯定不會限制他們。如果程序?qū)淼木S護人員需要擴展代碼以包含以前不存在的子類,那么只要他們擁有對源代碼的訪問權(quán)(如果他們無權(quán)訪問,那么如何成為該代碼的“維護人員”呢?),刪除相應(yīng)類上的 final 關(guān)鍵字并重新編譯并不太困難。

??同時,那個被添加的關(guān)鍵字充當關(guān)于該程序的重要不變量的自動驗證文檔形式(“自動驗證”是因為如果該文檔被破壞,那么該程序甚至不會編譯)。通過強制開發(fā)人員自覺選擇何時要刪除這樣的不變量,我們可以幫助減少錯誤的引入。

??單元測試和變化
??單元測試總是能夠有助于理解具有副作用的代碼。如果一套單元測試充分證明了方法在程序中的作用,那么程序員只要通過閱讀其單元測試就可以更迅速理解每個方法。當然,單元測試是否真的涵蓋了所有的作用是個大問題。類似于 Clover 的有效范圍分析工具在這里可以提供某種程度的幫助。

??但是,請注意單元測試本身要比編寫嚴格的函數(shù)方法簡單得多。要測試嚴格的函數(shù)方法,涉及的全部就是用各種具有代表性的輸入調(diào)用這些方法,并檢查它們的輸出(并確保它們在應(yīng)該拋出異常時能拋出)。

??在測試修改數(shù)據(jù)結(jié)構(gòu)狀態(tài)的方法時,我們必須首先執(zhí)行這樣的操作,這些操作是將輸入數(shù)據(jù)放入該方法所期望的狀態(tài)中所需要的,然后在調(diào)用該方法之后,檢查是否正確執(zhí)行了客戶機所期望的數(shù)據(jù)的每次修改。

??用重構(gòu)工具封裝
??在編寫新代碼時這些技巧很有用,但是當您必須維護幾乎不能譯碼的舊代碼時,怎么辦呢?重構(gòu)、重構(gòu)、還是重構(gòu)。

??盡管重構(gòu)舊代碼很費時,但是這些時間是值得的,特別是所有支持重構(gòu)的工具現(xiàn)在也支持 Java 代碼了,F(xiàn)在已經(jīng)有許多自動重構(gòu) Java 代碼的強大工具,這些工具可以自動保存關(guān)鍵的不變量。

??重構(gòu) Java 代碼的一個功能相當齊全的工具是 IDEA 開發(fā)環(huán)境。該環(huán)境對相當多的 Martin Fowler 重構(gòu)模式提供自動支持。我找到的另一個非常有用的工具是 CodeGuide,它是一個來自德國的 IDE。盡管相對于 IDEA,其自動重構(gòu)的列表很小,但是它顯示了一個極其強大的特性 ? 連續(xù)編譯。當您輸入新代碼時,CodeGuide 分析它并告知您項目中是否不完整(當然,這產(chǎn)生很短的延遲,它防止對每次擊鍵發(fā)出錯誤信號)。

??盡管連續(xù)編譯對響應(yīng)產(chǎn)生負面影響,但是在某些上下文中非常值得這樣的等待。例如,您可以在字段前輸入 final,會立即看到項目中是否不完整。如果無,那么您知道該字段在該程序的任何地方都沒有被修改。同樣,您可以在字段之前輸入 private,那么立即獲得對該字段的所有外部訪問的列表(以錯誤的形式)。

??CodeGuide 的另一個極佳特性是它用泛型類型對 JSR-14 實驗擴展提供了無縫支持(計劃正式添加到 Java 1.5)。

??盡管為了可譯碼性而編寫代碼會花費非常多的時間和精力,但是它會有助于提高代碼的生命期和健壯性,而且它可以顯著提高面臨維護代碼任務(wù)的那些程序員的生活質(zhì)量。最后,重構(gòu)舊代碼使之

標簽: 代碼 計劃 問題 選擇

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請與原作者聯(lián)系。

上一篇:Google CEO安撫用戶 稱搜索記錄不會被泄露

下一篇:戴爾直銷網(wǎng)站標錯價 三小時損失千萬元