您好,登錄后才能下訂單哦!
如何實現防御式編程?針對這個問題,今天小編總結這篇有關防御式編程的文章,希望能幫助更多想解決這個問題的朋友找到更加簡單易行的辦法。
防御式編程的全部重點就在于防御那些你未曾預料到的錯誤。
防御式編程的主要思想:子程序應該不因傳入錯誤數據而被破壞,哪怕是由其他子程序產生錯誤數據。更一般地說,其核心想法是要承認程序都會有問題,都需要被修改,聰明的程序員應該根據這一點來編程序。
一、保護程序免遭非法輸入數據的破壞
對已形成產品的軟件而言:不管進來的數據如何,都不應該產程垃圾數據。(必要的錯誤提示)
通常有三種方法來處理進來的垃圾數據:
1、檢查所有來源于外部的數據的值
當從文件、用戶、網絡或其他外部接口中獲取數據時,應檢查所獲得的數據值,以確保它在允許的范圍內。
2、檢查子程序所有輸入參數的值
數據來源于其他子程序,而不是外部接口。
3、決定如何處理錯誤的輸入數據
一旦檢測到非法數據,就應該處理它。
注:防范看似微小的錯誤,收獲可能遠遠超出你的想象。
二、斷言(Assertions)
斷言定義:指在開發期間使用的,讓程序在運行時進行自檢的代碼(通常可以是子程序或宏)。(對大型的復雜程序或可靠性要求極高的程序來說尤其重要)
Java斷言:兩個參數—>assert(“bool表達式”,“當判斷條件為false時的錯誤信息”)
斷言檢查如下這類假定:
1、 輸入參數和輸出參數的取值處于預期的范圍內。
2、 子程序開始(或結束)執行時,文件或流是處于打開(或關閉)的狀態。
3、 子程序開始(或結束)執行時,文件或流的讀寫位置處于開頭(或結尾)處。
4、 文件或流已用只讀、只寫或可讀可寫方式打開。
5、 僅用于輸入的變量的值,沒有被子程序所修改。
6、 指針非空。
7、 傳入子程序的數組或其他容器至少能容納X個數據元素。
8、 表已經初始化,存儲著真實的數據。
9、 子程序開始(或結束)執行時,某個容器是空的(滿的)。
注:斷言主要是用于開發和維護階段,而在生成產品代碼時并不編譯到目標代碼中,以免降低系統性能。
1、建立自己的斷言機制
※ C++、Java、VB在內的很多語言都支持斷言。
※ C++中標準的assert宏并不支持文本信息。
2、使用斷言的指導建議
斷言的指導建議:
用錯誤處理代碼來處理預期會發生的狀況,用斷言來處理決不應該發生的狀況。
異常發生,觸發斷言的情況下,就應該修改程序的源代碼并重新編譯。避免把需要執行的代碼放到斷言中
※ 一種危險的斷言使用方法(如果斷言關閉,代碼不能被編譯):
Debug.Assert( PerformAction() )
※ 安全地使用斷言
actionPerformed = PerformAction()
Debug.Assert( actionPerformed )用斷言來注解并驗證前條件和后條件
※ 如果數據來源于系統外部,那么就應該用錯誤處理代碼來檢查和處理非法的數值。
※ 如果變量的值來源于可信的系統內部,那么使用斷言是很合適的。對于高健壯性的代碼,應該先使用斷言再處理錯誤
※ Microsoft Word,在其代碼中,對應該始終為真的條件都加上了斷言,但同時也用錯誤處理代碼處理了這些錯誤,以應對斷言失敗的情況。
三、錯誤處理技術
如何處理那些預料中的程序錯誤:
※ 返回中立值、換用下一個正確數據、返回與前次相同的值、換用最接近的有效值、在日志文件中記錄警告信息、返回一個錯誤碼、調用錯誤處理子程序或對象、顯示出錯信息或關閉程序。
1、返回中立值
※ 有時,處理錯誤的最佳做法就是繼續執行操作并簡單地返回一個沒有危害的數值。
※ 例如:數值操作可以返回0、字符串操作可以返回空字符串、指針操作可以返回空指針。
2、換用下一個正確的數據
※ 例如:數據庫記錄讀取、文件行信息讀取等。
3、返回與前次相同的數據
4、換用最接近的合法值
※ 例如:汽車的速度表無法顯示負的速度,所以在倒車時,它簡單的顯示為0。
5、把警告信息記錄到日志文件中
※ 要考慮是否能夠安全地公開它,或者是否需要對其進行加密或實施其他方式的保護。
6、返回一個錯誤碼
※ 可以決定在讓系統得某些部分處理錯誤,其他部分則不在本地(局部)處理錯誤,而只是簡單地報告說有錯誤發生。
采用方法:
※ 設置一個狀態變量的值
※ 用狀態值作為函數的返回值
※ 用語言內建的異常機制拋出一個異常
注:如果安全性很重要,請確認調用方的子程序總會檢查返回的錯誤嗎。
7、調用錯誤處理子程序或對象
※ 可以把錯誤處理都集中在一個全局的錯誤處理子程序或對象中進行。
※ 優點:能把錯誤處理的職責集中在一起,從而讓調試更為簡單。
缺點:整個程序都要知道這個集中點,并與之緊密耦合。
8、當錯誤發生時顯示出錯消息
※ 可以把錯誤處理的開銷降低。
9、用最妥當的方式在局部處理錯誤
※ 給程序員帶來靈活度的同時,也帶來了顯著的風險。即:系統的整體性能將無法滿足對其正確性或可靠性的需求。
10、關閉程序
※ 適用于人身安全攸關的應用程序。
健壯性與正確性
※ 處理錯誤最恰當的方式要根據出現錯誤的軟件的類別而定。錯誤處理有時更側重于正確性,有時更側重于健壯性。
※ 正確性:意味著永不返回不準確的結果,哪怕不返回結果也比返回不準確的結果要好。
※ 健壯性:意味著要不斷嘗試采取某些措施,以保證軟件可以持續地運轉下去,哪怕有時做出一些不夠準確的結果。
高層次設計對錯誤處理方式的影響
※ 在整個程序里采用一致統一的方式來處理非法的參數。
※ 確定一種通用的處理錯誤參數的方法,是架構層次(高層次)的設計決策。
※ 一旦確定了某種方法,就要確保始終如一地貫徹這一方法。
※ 請在每個系統調用后檢查錯誤碼。
四、異常
處理異常建議:
1、用異常通知程序的其他部分,發生了不可忽略的錯誤
※ 異常機制的優越之處就在于它能提供一種無法被忽略的錯誤通知機制。
2、只在真正例外的情況下才拋出異常
※ 僅在其他編碼實踐方法無法解決的情況下才使用異常。
※ 異常同斷言相似:都是用來處理那些不僅罕見甚至永遠不該發生的情況。
※ 異常的取舍:
1、異常是一種強大的用來處理預料之外的情況途徑。
2、程序的復雜度因此增加、性能也可能降低。
3、不能用異常來推卸責任
※ 能在局部處理的錯誤,就應該在局部處理,不能當成異常拋出。
4、避免在構造函數和析構函數中拋出異常,除非你在同一地方把他們捕獲
※ 如果在構造函數中拋出異常,就不會調用析構函數,從而造成潛在的資源泄漏。
5、在恰當的抽象層次拋出異常
※ 當你決定把一個異常傳給調用方時,請確保異常的抽象層次與子程序接口的抽象層次相一致。
6、在異常消息中加入關于導致異常發生的全部信息
※ 要確保異常信息中含有為理解異常拋出原因所需要的全部信息。
7、避免使用空的catch語句
※ 注釋或日志記錄信息對這一情況文檔化。
8、了解所有函數庫可能跑出的異常
※ 一定要了解所用的函數庫都會拋出哪些異常。
※ 未能捕獲由函數庫拋出的異常將會導致程序崩潰。
9、考慮創建一個集中的異常報告機制
※ 能為一些與異常有關的信息提供一個集中的存儲,如發生的異常種類、每個異常該如何被處理以及如何格式化異常信息。
10、把項目中對異常的使用標準化
※ 如果使用象C++一樣的語言,就應該規定到底可以拋出哪些種類的異常。(考慮只拋出std::exception基類派生出的對象)
※ 考慮創建項目特定的異常類(用作項目可能異常的基類,這樣就能把紀錄日志、報告錯誤等操作集中起來并標準化)。
※ 規定在何種場合允許代碼使用try-catch語句在局部對錯誤進行處理。
※ 規定在何種場合允許代碼拋出不在局部進行處理的異常。
※ 確定是否要使用集中的異常報告機制。
※ 規定是否允許在構造函數和析構函數中使用異常。
11、考慮異常的替換方案
※ 請考慮你的系統是否真的需要異常。
五、隔離程序,使之包容由錯誤造成的損害
隔欄(barricade)是一種容損策略。
1、在類的層次采用這樣的方法:
※ 類的public方法可以假定數據是不安全的,它們要負責檢查數據并進行清理,一旦類的公用方法接受了數據,那么類的私有方法就可以假定數據都是安全的了。
2、隔欄與斷言的關系:
※ 隔欄的使用使斷言和錯誤處理有了清晰的區別。
※ 隔欄外部的程序應該適用錯誤處理技術,而隔欄內部的程序就應該使用斷言技術。
六、輔助調試的代碼
防御式編程的另一個重要方面就是,適用調試助手(輔助調試代碼)。
1、不要自動地把產品版的限制強加于開發版之上
※ 程序員常常有這樣一個誤區:即認為產品級軟件的種種限制也應該在開發版本中得到體現(速度、對資源的限制)。
※ 應該在開發階段犧牲一些速度和資源使用,來換取一些可以讓開發順暢的內置工具(輔助代碼)。
2、盡早引入輔助調試代碼
※ 越早引入輔助調試的代碼,它能提供的幫助也就越大。
3、采用進攻式編程
※ 應該以這么一種方式來處理異常:在開發階段讓它顯現出來,而在產品代碼運行時讓它能夠自我恢復。--- “進攻式編程”
進行進攻式編程的方法:
確保斷言語句是程序終止運行。
完全填充分配到的所有內存,這樣可以讓你檢測到內存分配錯誤。
4、計劃移除調試輔助的代碼
※ 要事先做好計劃,避免調試代碼和程序代碼糾纏不清。
采取的方法:
※ 使用類似ant和make這樣的版本控制工具和make工具
(可以從同一套源碼編譯出不同版本的程序)
※ 使用內置的預處理器
※ 編寫你自己的預處理器
※ 使用調試存根(stubs)
(兩套方案—開發版本和發布版本代碼)
七、確定在產品代碼中該保留多少防御式代碼
八、對防御式編程采取防御的姿態
看完這篇文章,你們學會使用防御式編程了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。