1. 程式人生 > 其它 >軟體構造-10 面向可維護性的構造技術

軟體構造-10 面向可維護性的構造技術

本章面向可維護性:軟體發生變化時,是否可以以很小的代價適應變化?

(本章偏理論,主要為記憶性內容,本部落格僅為簡單的記錄與整理)

1.軟件可維護性及其演化

  •  軟體可維護性型別:  糾錯性(25%),適應性(21%),完善性(50%),預防性(4%)
  •  軟體維護不僅僅是運維工程師的工作,而是從設計和開發階段就開始了/在設計與開發階段就要考慮將來的可維護性/設計方案要“easy to change”

     

2.可維護性指標

     1.可維護性別名:可維護性,可擴充套件性,靈活性,可適應性,可管理性,支援性

     2.code review時關於可維護性經常會問的問題:

               設計結構是否足夠簡單

               模組之間是否鬆散耦合

               模組內部是否高度聚合

               是否使用非常深的繼承樹

               是否使用delegation替代繼承

               程式碼的圈/環複雜度是否太高

               是否存在重複程式碼

    3.常用可維護性度量:

               1)圈/環複雜度:獨立路徑的數量 CC=number of areas

               2)程式碼行數

               3)Halstead Volume:多少獨立算符

               4)可維護性指數(MI):

                  

                5)繼承的層次數

                6)類之間的耦合度(儘量減少非常複雜的相互呼叫)

                7)單元測試的覆蓋度

3. 模組化設計和模組化原則

               模組化程式設計:高內聚,低耦合(多模組之間關聯較小,防止一個模組的大幅度改變影響另一個模組),分離關注點,資訊隱藏

(1) 評估模組化的五個標準:

  1. 可分解性:能否容易分解成各個可獨立解決的子問題,是模組之間的依賴關係顯式化和最小化
  2. 可組合性:能夠容易將多個模組組合起來形成新的系統,使模組在不同的環境下複用
  3. 可理解性:每個部分都可以被獨立的理解
  4. 可持續性:發生變化時受影響範圍最小
  5. 出現異常之後的保護:出現異常後受影響範圍最小

(2) 模組化設計的五個原則:

  1. 直接對映:模組的結構與現實世界中問題領域的結構保持一致-》持續性,可分解性
  2. 儘可能少的介面:模組應儘可能少的與其他模組通訊-》可持續性、保護性、可理解性、可組合性
  3. 儘可能小的介面:如果兩個模組通訊,那麼它們應交換儘可能 少的資訊-》可持續性,保護性
  4. 顯式介面:當A與B通訊時,應明顯的發 生在A與B的介面之間-》可分解性、可組合性、可持續性、 可理解性

       

        5.資訊隱藏:經常可能發生變化的設計決策應 儘可能隱藏在抽象介面後面

(3)耦合和內聚:

        1.耦合:模組間的介面數目,每個介面的複雜度

        2.內聚:模組內部的方法聯絡是否緊密

4. 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)責任:變化的原因

            3)不應有多於1個的原因使得一個類發生變化

            4)包含多個責任會導致:– 引入額外的包,佔據資源

                                                      – 導致頻繁的重新配置、部署等

            5)一個類,一個責任

(2)OCP:(面向變化的)開放/封閉原則

            1)對擴充套件性的開放:模組的行為應是可擴充套件的,從而該模組可表現出新的行為以滿足需求的變化

            2)對修改的封閉:但模組自身的程式碼是不應被修改的/擴充套件模組行為的一般途徑是修改模組的內部實現/如果一個模組不能被修改,那麼它通常被認為是具有固定的行為

            3)關鍵解決方案:抽象技術(儘量少用具體的)

(3)LSP:Liskov替換原則

            子型別必須能夠替換其基型別/派生類必須能夠通過其基類的介面使用,客戶端無需瞭解二者之間的差異

(4)ISP:介面隔離原則

             1)不能強迫客戶端依賴於它們不需要的介面:只提供必需的介面

             2)避免介面汙染/避免胖介面

(5)DIP:依賴轉置原則

             1)高層模組不應該依賴於低層 模組,二者都應該依賴於抽象

             2)抽象不應該依賴於實現細節,實現細節應該依賴於抽象

             OO設計的兩大武器:抽象(LSP,DIP,OCP)/分離(SPR,ISP)

5. 語法驅動的構造

            有一類應用,從外部讀取文字資料,在應用中做進一步處理 

            正則表示式:根據語法,開發一個它的解析器,用於後續的解析(不變的直接用‘’裡的字元表示,其餘可變的用符號組合表示,中間有比較複雜的模組就進行命名,單獨脫離出來也寫成一個表示式,比如下面eg中的hostname)

(1)基本操作:

            – Concatenation 連線: x ::= y z     (x匹配y與z連線)

            – Repetition 重複:     x ::= y*         (x匹配0或更多個y)(自動機裡的克林閉包?)

            – Union 選擇 :        x ::= y | z         (x匹配y或者z)

           eg:

          

(2)更多操作:

          1)選擇 (出現0或1次),用 ? 表示 :

                    x ::= y?         (x匹配y或者空)

          2)出現1次或更多次 ,用 + 表示:

                    x ::= y+         (x匹配一個或更多y,與 x ::= y y*相等 )

          3)字元類 [...],表示長度為 1 的字串,其中包含任何一個方框中列出的字元:

                    x ::= [a-c]   等同於  x ::= 'a' | 'b' | 'c'

                    x ::= [aeiou]   等同於   x ::= 'a' | 'e' | 'i' | 'o' | 'u'

          4) 倒排字元類 [^...],表示長度為 1 的字串,其中包含括號中未列出的任何字元:

                    x ::= [^a-c]  等同於 x ::= 'd' | 'e' | 'f' | ...

(3)優先順序:* ? +優先順序最高,連線次之,| 最低

(4)在Java中使用正則表示式:

           1)使用java.util.regex包中的三個類:

                    1>Pattern:Pattern物件是對regex正則表示式進行編譯之後得到的結果

                    2>Matcher: 利用Pattern對輸入字串進行解析

                    3>PatternSyntaxException:object 是一個未經檢查的異常,表示正則表示式中的語法錯誤

           2)eg:

                  

 (5)字元類:

                    

(6)預定義字元類:

                   

 (7)量詞: