軟件構造(8)- 可維護性與健壯性

可維護性的軟件構造技術

一.可維護性的常見度量指標:
  1. 圈複雜度:圈複雜度大說明程序代碼可能質量低且難於測試和維護
  2. 代碼行數
  3. 可維護性指數(MI):0-100 利用公式計算
  4. 繼承的層次數:層次越多越不好維護。CRP原則,儘量使用代理而不是繼承。
  5. 類之間的耦合度
  6. 單元測試的覆蓋度
二.聚合度與耦合度:

1.耦合度:衡量兩個模塊間的依賴關係,即其中一個模塊的變化是否影響另一個
影響因素:模塊間接口的數量和每個接口的複雜程度
2.內聚:衡量模塊內的方法或屬性的關聯關係的強弱
模塊之間聯繫越緊密,其耦合性就越強,模塊之間獨立性則越差
追求高內聚低耦合

三.OO設計原則:SOLID
  • (SRP) The Single Responsibility Principle 單一責任原則
  • (OCP) The Open-Closed Principle 開放-封閉原則
  • (LSP) The Liskov Substitution Principle Liskov替換原則
  • (DIP) The Dependency Inversion Principle 依賴轉置原則
  • (ISP) The Interface Segregation Principle 接口聚合原則
  1. SRP:不應該有多於1個原因讓你的ADT發生變化,否則就拆分開
    否則會導致:1. 引入額外的包,佔據資源 2. 導致頻繁的重新配置、部署等

  2. OCP:開放封閉原則
    對擴展性的開放:模塊的行爲應是可擴展的,從而該模塊可表現出新的行爲以滿足需求的變化
    對修改的封閉:1. 模塊自身的代碼是不應被修改的。 2. 擴展模塊行爲的一般途徑是修改模塊的內部實現。3. 如果一個模塊不能被修改,那麼它通常被認爲是具有固定的行爲

  3. LSP
    子類型必須能夠替換其基類型
    派生類必須能夠通過其基類的接口使用,客戶端無需瞭解二者之間的差異

  4. ISP:接口隔離原則
    不能強迫客戶端依賴於它們不需要的接口:只提供必需的接口
    將含有多個功能的接口分解爲多個小接口,不同的接口向不同的客戶端提供服務,客戶端只訪問自己所需要的端口

//bad example (polluted interface)
interface Worker {
	void work();
	void eat();
}
ManWorker implements Worker {
	void work() {…};
	void eat() {…};
}
RobotWorker implements Worker {
	void work() {…};
	void eat() {//Not Appliciable for a RobotWorker};
}
//Solution: split into two
interface Workable {
	public void work();
}
interface Feedable{
	public void eat();
}
//只需實現對應的接口即可
  1. DIP:依賴轉置原則
    delegation的時候,要通過interface建立聯繫,而非具體子類

健壯性

健壯性:系統在不正常輸入或不正常外部環境下仍能夠表現正常的程度
正確性:程序按照spec加以執行的能力,是最重要的質量指標!

健壯性:儘可能保持軟件運行而不是總是退出
正確性:永不給用戶錯誤的結果

健壯性與正確性的比較

正確性傾向於直接報錯(error),健壯性則傾向於容錯(fault-tolerance)
健壯性:
讓用戶變得更容易:出錯也可以容忍,程序內部已有容錯機制
正確性:
讓開發者變得更容易:用戶輸入錯誤,直接結束。(不滿足precondition的調用)

對外的接口,傾向於健壯;對內的實現,傾向於正確

錯誤與異常

在這裏插入圖片描述
Error:程序員通常無能爲力,一旦發生,想辦法讓程序優雅的結束
發生的原因:用戶輸入錯誤,設備錯誤,物理限制
Exception:程序的問題,可以捕獲處理

異常處理

異常:程序執行中的非正常事件,程序無法再按預想的流程執行
將錯誤信息傳遞給上層調用者,並報告“案發現場”的信息
return之外的第二種退出途徑

異常的種類

  1. 運行時異常:由程序員在代碼裏處理不當造成
    程序源代碼中引入的故障所造成的 ;例如:ArrayIndexOutOfBoundsException, NullPointerException
    如果在代碼中提前進行驗證,這些故障就可以避免
  2. 其他異常:由外部原因造成
    程序員無法完全控制的外在問題所導致的;例如:FIleNotFoundException
    即使在代碼中提前加以驗證(文件是否存在),也無法完全避免失效發生。

Checked exceptions:
需要從Exception派生出子類型
必須捕獲並指定錯誤處理器handler,否則編譯無法通過,類似於靜態類型檢查
在這裏插入圖片描述
Unchecked exceptions:
從RuntimeException派生出子類型
可以不處理,編譯沒問題,但執行時出現就導致程序失敗,代表程序中的潛在bug,類似於動態類型檢查。
也可捕獲,但不需要----相當於已知代碼中的錯誤但不進行修改
eg:ArrayIndexOutOfBoundsException,NullPointerException
在這裏插入圖片描述
異常處理中的關鍵字:
Declaring exceptions (throws) 聲明“本方法可能會發生XX異常” —在spec中使用
Throwing an exception (throw) 拋出XX異常
Catching an exception (try, catch, finally) 捕獲並處理XX異常

Checked exceptions和Unchecked exceptions的區別
在這裏插入圖片描述
子類型異常處理規範:(LSP)

  1. 如果子類型中override了父類型中的函數,那麼子類型中方法拋出的異常不能比父類型拋出的異常類型更寬泛
  2. 子類型方法可以拋出更具體的異常,也可以不拋出任何異常
  3. 如果父類型的方法未拋出異常,那麼子類型的方法也不能拋出異常。

finally語句:
當異常拋出時,方法中正常執行的代碼被終止
如果異常發生前曾申請過某些資源,那麼異常發生後這些資源要被恰當的清理
try-catch-finally結構

  1. 當try中代碼不拋出異常時
    不管程序是否碰到異常,finally都會被執行
  2. try中代碼拋出異常被catch捕獲
    處理結束後仍會執行finally

在這裏插入圖片描述
但如果catch塊中出現throws異常 上圖只會執行1 3 5

  1. try中代碼拋出異常但未被catch捕獲
    出現異常後,try中剩餘的語句會被跳過,然後finally執行,並將異常返回給調用者
    eg:如下程序只執行1.5
    在這裏插入圖片描述
斷言與防禦式編程

避免引入bug

  1. 靜態類型檢查
  2. 動態類型檢查
  3. 不可變性
  4. 不可變的值:final修飾
  5. 不可變引用:final修飾

限制bug作用範圍

  1. 限定在一個方法內部,不擴散
  2. fail fast:儘快失敗,就容易發現、越早修復
    Pre-condition如果違反,該方法可以做任何事
    應該儘可能早的指出client的bug

斷言Assertions
斷言:在開發階段的代碼中嵌入,檢驗某些“假設”是否成立。若成立,表明程序運行正常,否則表明存在錯誤。出現AssertionError,意味着內部某些假設被違反了
使用斷言的主要目的是爲了在開發階段調試程序、儘快避免錯誤
eg:檢測pre-condition 是否成立

assertion使用規範:

assert condition ;
//所構造的message在發生錯誤時顯示給用戶,便於快速發現錯誤所在
assert condition : message;

可檢測的情況:

  1. 內部不變量:assert x>0;
  2. 表示不變量:checkRep();
  3. 控制流不變量:在控制流不應該到達的位置添加斷言 eg:switch-case中的default
  4. 方法的前置條件
  5. 方法的後置條件

不可使用的情況:

// don't do this: 
x = y + 1; 
assert x == y+1;

// don't do this: 因爲代碼中的assert可被disable,需要執行的程序結構不能在assert中
assert list.remove(x);
// do this: 
boolean found = list.remove(x); 
assert found;

斷言非常影響運行時的性能,可使用-da進行disable

斷言與異常的比較

使用異常來處理你“預料到可以發生”的不正常情況
使用斷言處理“絕不應該發生”的情況

如果參數來自於外部(不受自己控制),使用異常處理
如果來自於自己所寫的其他代碼,可以使用斷言來幫助發現錯誤,檢測非public類中的前置條件和所有方法中的postcondition

斷言和異常處理都可以處理同樣的錯誤
開發階段用斷言儘可能消除bugs,在發行版本里用異常處理機制處理漏掉的錯誤

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章