簡介
軟件結構設計是對組成系統的各個子系統的進一步分解與規划。例如,將子系統按照其功 能要素分解成具有一定的功能邊界的模塊,然后以模塊為單位來構造軟件。顯然,需求分析階 段已經建立起的有關系統的功能模型、數據模型或狀態機模型,可以作為軟件結構設計的前提 依據。 具體說來,軟件結構設計包括以下幾方面的內容:
- 確定構造子系統的模塊元素。
- 定義每個模塊的功能。
- 定義模塊接口,設計接口的數據結構。
- 確定模塊之間的調用與返回關系。
- 評估軟件結構質量,進行結構優化。
模塊概念
模塊化
模塊概念產生於結構化程序設計思想,這時的模塊被作為構造程序的基本單元,例如函數、 過程。 在結構化方法中,模塊是一個功能單位,因此模塊可大可小。它可以被理解為所建軟件系 統中的一個子程序系統,也可以是子程序系統內一個涉及多項任務的功能程序塊,並可以是功 能程序塊內的一個程序單元,例如函數、過程。也就是說,模塊實際上體現出了系統所具有的 功能層次結構。 模塊可以使軟件系統按照其功能組成進行分解,而通過對軟件系統進行分解,則可以使一 些大的復雜的軟件問題分解成諸多小的簡單的軟件問題。從軟件開發的角度來看,這必然有利 於軟件問題的有效解決。對於這個結論,可以進行以下論證: 現假設函數 C ( P )用於度量問題 P 的復雜程度,函數 E ( P )用於度量為解決問題 P 所需 要的工作量(用時間計算)。並假設有兩個問題 P 1和 P 2。 如果有: C ( P 1)> C ( P 2) 則必有: E ( P 1)> E ( P 2) 這是一個顯而易見的經驗性結論。它表明:問題越復雜,解決這個問題所需要的工作量就 越大,需要花費時間就越多。 另一個來源於經驗的結論是: C ( P 1 + P 2)> C ( P 1)+ C ( P 2) 它表明:如果能夠把兩個結合在一起的問題隔離開來單獨解決,則可以使這原本結合在一 起的問題的復雜程度下降。 顯然,從上面兩個經驗性結論中可以作出以下推論: E ( P 1 + P 2)> E ( P 1)+ E ( P 2) 它表明:如果能夠把兩個結合在一起的問題隔離開來單獨解決,則可以使這原本難於解決 的問題變得容易解決起來。這個結論就是模塊化的基本依據,其作用就是能夠使大的復雜的問 題被“各個擊破”。 上述結論表明:模塊化可以使軟件問題簡化。但是,得出這個結論需要有下面的前提條件: 大模塊被分解成諸多小模塊之后,小模塊基本上處於相互隔離的獨立狀態,它們之間沒有太多 的通信。否則,小模塊之間由於存在太多的通信,將會導致小模塊接口復雜起來,其結果是, 雖然每個模塊內部簡化了,但整個軟件問題反而復雜起來。 許多人都有一個良好的願望,那就是依靠模塊化使系統不斷分解而使整個系統不斷簡化, 由此使軟件開發成本不斷下降。然而這卻可能做不到,因為隨着系統的分解,系統中模塊數目 將會增加,模塊接口也會增加,軟件構造會由此變得復雜起來,模塊連接的難度也會由此加大。實際上還有一個因素也在阻礙着這個願望的實現,這就是軟件系統的模塊化分解本身也是一件 並不輕松的工作,假如分解系統所需要的工作量,已經超過因為模塊簡化而減少的工作量,那 就意味着,進一步分解系統已是一件得不償失的事情了。 因此,軟件系統模塊化分解,從軟件成本角度來看,有一個最小成本模塊數范圍。如下圖 所示,若分解程度低於這個最小成本模塊數范圍,則可繼續分解,以降低軟件開發成本;但若 分解程度已經達到這個最小成本模塊數范圍,則就沒有必要再進行分解了,否則將會反而增加 軟件開發的成本。
抽象化
抽象是人所具有的一種高級思維活動,是以概括的方式抽取一系列事物的共同特征,由此 把握事物的本質屬性。抽象也是人類解決復雜問題時強有力的手段,能夠使人從事物復雜的外 部表象中發現事物的內在本質規律,由此找到解決問題的有效途徑。 這種抽象的方法也被運用於軟件工程之中。實際上,軟件工程的每一個階段,都能夠看到 抽象思維方法的作用,從軟件的定義到軟件的設計,直到軟件編碼與最終實現。但是,在軟件工程的不同階段,抽象層次與對象卻各不相同,並需要運用不同的語言進行描述。例如,在軟件分析階段,抽象對象是系統的外部特征,需要采用的描述語言是軟件問題所處環境中的用戶 術語;而在設計階段,抽象對象則是系統的內部構造,需要采用的描述語言則是更加規范的適 合於系統構造的過程化語言。 概要設計中的功能模塊往往被看成是一個抽象 化的功能黑盒子,其特征如圖 5-13 所示。雖然它已 是一個與軟件實現直接相關的實體單元,可以看到 它清晰的外觀,但是卻看不到它內部更加具體的實 現細節。 抽象的作用是對事物現象的高度概括,但抽象 的最終目的則是走到它的對立面,產生出具體的結 果。因此,一個完整的抽象化過程是既包含抽象又 包含具體的循環演變過程。應該說,正是由抽象到具體的不斷演變,才使得人的抽象認識能夠不斷地產生出有意義的結果,並不斷地推動着人類 思想的進步。 這種由抽象到具體的不斷演變也一直貫穿於軟件工程過程之中,這就是自頂向下、逐步細 化,其中,頂是抽象的,而細化則是這個抽象的頂具體化的結果。這意味着,軟件工程的每一 個階段的推進,都具有從抽象到具體的轉化。 例如需求分析,它建立在可行性研究基礎之上。可行性研究所獲得的是有關整個計算機系 統的外部模型,這是一種對整個系統的高度抽象。但是,隨着需求分析的進行,可行性研究中 高度抽象的系統模型被逐步地轉變成需求分析模型中每一個功能局部的規格定義。顯然,這是 軟件從高層定義到低層定義的具體化演變。 又如概要設計,它是在需求分析基礎上進行的,需要根據需求分析中的基本要求設計軟件 系統的基本構架,需要按照需求分析所提出的功能規格,確定軟件系統中模塊的構成,定義模 塊的接口,確定模塊之間通信,設計對模塊的控制。顯然,這是軟件從系統定義到系統設計的 具體化演變。 應該說,概要設計中的結論,對於軟件內部構造而言則仍是抽象的。比如概要設計中的功 能模塊,盡管它有惟一的名稱標識,有明確的功能定義,並設置有數據的輸入輸出接口。但是, 模塊的內部實現細節則處於待定狀態,需要等到詳細設計完成以后才能得出更加具體的算法結論。
信息隱藏
設計軟件結構時一個不可回避的問題是:為了得到一種高質量的模塊組合,應該如何分解 軟件。對此,不得不了解什么是“信息隱蔽”。 信息隱蔽是指每個模塊的內部實現細節對於其他模塊來說是隱蔽的。也就是說,模塊中所 包含的信息,例如,模塊內部的數據、語句或過程等,不允許其他不需要這些信息的模塊使用。 顯然,信息隱蔽有利於模塊相互之間的隔離,可以使每個模塊更加具有獨立性,並可以使模塊 之間的通信受到限制。例如,模塊之間只能傳遞那些對於其功能實現而言是必須的信息。 通過限制模塊需要使用的數據的作用范圍,例如,定義模塊內部局部變量,可以產生出模塊內部信息隱蔽的效果。 模塊內部信息隱蔽的好處是可以使軟件系統更加健壯,更加方便維護。 以模塊中的錯誤為例,假如模塊內部信息是隱蔽的,則模塊中存在的這個錯誤將比較難於擴散到其他模塊。否則,系統可能因為一個小錯誤的擴散,而使整個系統崩潰。實際上,信息 隱蔽還使軟件錯誤定位更加方便。由於軟件出錯位置容易發現,因此,整個軟件糾錯工作的效 率、質量都會隨之提高。 一些模塊的功能有時需要根據用戶需求的變更而適時地進行一些功能改造。當需要對模塊 進行功能改造時,模塊內部的信息隱蔽會使對模塊改造所帶來的影響限制在需要改造的模塊之 內,而與其他模塊無關。顯然,這將使軟件系統的局部修改變得更加便利。
模塊的獨立性
模塊的獨立性是指軟件系統中每個模塊都只涉及自己特定的子功能,並且模塊接口簡單, 與軟件中其他模塊沒有過多的聯系。
模塊獨立性是衡量軟件中模塊質量最重要的指標,是設計與優化軟件結構時必須考慮的重要因素。當軟件中的每個模塊都具有很好的獨立性時,軟件系統不僅更加容易實現,並且會使今后的維護更加方便。 模塊的獨立性一般采用耦合和內聚這兩個定性的技術指標進行度量。其中,耦合用來反映 模塊之間互相連接的緊密程度,模塊之間的連接越緊密,聯系越多,耦合性就越高。內聚用來反映模塊內部各個元素彼此結合的緊密程度,一個模塊內部各個元素之間結合越緊密,則它的 內聚性就越高。顯然,為了使模塊具有較強的獨立性,要求模塊是高內聚、低耦合。
耦合
耦合是軟件結構中各個模塊之間相互關聯程度的度量。耦合的強弱取決於各個模塊之間接 口的復雜程度、接口數據對模塊內部計算的影響程度和調用模塊的方式。 模塊之間的耦合形式主要有:非直接耦合、數據耦合、控制耦合、公共耦合和內容耦合。 其中,非直接耦合和數據耦合是較弱的耦合,控制耦合和公共耦合是中等程度的耦合,內容耦 合則是強耦合。 模塊化設計的目標是盡量建立模塊間耦合松散的系統。因此,在設計軟件結構時一般也就 要求盡量采用非直接耦合和數據耦合,少用或限制使用控制耦合和公共耦合,絕對不能使用內 容耦合。 為了更好地認識模塊之間的耦合,下面將對上述各種耦合形式給出必要說明。
a.非直接耦合
如果兩個模塊之間沒有直接關系,它們之間的聯系僅限於受到共同主模塊的控制與調用, 則稱這種耦合為非直接耦合。 由於非直接耦合的模塊之間沒有數據通信,因此模塊的獨立性最強。
b.數據耦合
當一個模塊訪問另一個模塊時,如果彼此之間是通過模塊接口處的參數實現通信,並且參 數所傳遞的數據僅用於計算,而不會影響傳入參數模塊的內部程序執行路徑,則稱這種耦合為 數據耦合。 數據耦合是一種松散的耦合。依靠這種類 型的耦合,模塊之間既能實現通信,又有比較 強的獨立性。因此,軟件結構設計中提倡使用 這類耦合
c.控制耦合
當一個模塊訪問另一個模塊時,如果彼此 之間是通過模塊接口處的參數實現通信,並且 參數傳遞了開關、標志、名字等控制信息,由 此影響了傳入參數模塊的內部程序執行路徑, 則稱這種耦合為控制耦合如圖 5-14 所示。 由於接口參數影響着內部程序執行路徑, 因此控制耦合比數據耦合要強一些,會使模塊 的獨立性有所下降。當需要通過一個單一的接口傳遞模塊內多項功能的選擇信息時,往往需要用到控制耦合。顯然,在控制耦合形式下,對 所控制模塊的修改,需要受到控制參數的限制。
d.公共耦合 公共耦合是一種通過訪問公共數據環境而實現通信的模塊耦合形式,例如,獨立於模塊而 存在的數據文件、數據表集、公共變量等,都可以看作為公共數據環境。 公共耦合中的公共數據環境是提供給任何模塊的,當模塊之間的耦合是公共耦合時,那些 原本可以依靠接口提供的對數據的限制也就沒有了。因此,相比依靠接口的耦合形式,公共耦 合必然會使模塊的獨立性下降。也正因為如此,實際應用中,只有在模塊之間需要共享數據, 並且通過接口參數傳遞不方便時,才使用公共耦合。 需要注意的是:模塊之間公共耦合的復雜程度,將會隨着耦合模塊個數的增加而顯著增加。 為了降低公共耦合帶來的復雜性和提高模塊的獨立性,實際應用中還會針對公共耦合專門設置 一些限制,例如不使用公共耦合數據傳遞控制信息。 下圖中的模塊采用了訪問公共數據環境的公共耦合形式。其中圖(a)是一個模塊只往 公共數據環境里送進數據,另一個模塊只從公共數據環境中取出數據,這是一種比較松散的公 共耦合;而圖(b)則是兩個模塊都可以向公共數據環境里送進數據,又都可以從公共數據環境 中取出數據,這就是一種比較緊密的公共耦合。
另外,公共耦合還會帶來以下一些方面的影響: • 由於所有公共耦合模塊都會與某一個公共數據環境有關,因此修改公共數據環境中某個 數據的結構,將會影響到所有被耦合的模塊。
• 由於沒有辦法控制各個模塊對公共數據的存取,因此公共耦合會影響軟件模塊的可靠性 和適應性。
• 由於公共數據環境需要被許多模塊使用,因此不得不使用具有公共意義的數據名稱。顯 然,這會使得程序的可讀性有所下降。
e.內容耦合 如果發生下列情形,兩個模塊之間就發生了內容耦合。
• 一個模塊直接訪問另一個模塊的內部數據。
• 一個模塊不通過正常入口轉到另一模塊內部。 • 兩個模塊有一部分程序代碼重疊。
• 一個模塊有多個入口。 內容耦合是一種非常強的耦合形式,嚴重影響了模塊獨立性。當模塊之間存在內容耦合時,模塊的任何改動都將變得非常困難,一旦程序有錯則很難修正。因此,設計軟件結構時,也就 要求絕對不要出現內容耦合。所幸的是,大多數高級程序設計語言已經設計成不允許出現內容 耦合,它一般只會出現在匯編語言程序中。
內聚
內聚是對模塊內部各個元素彼此結合的緊密程度的度量。模塊內部各個元素之間的聯系越緊密,則它的內聚程度就越高。模塊的設計目標是盡量使模塊的內聚程度高,以達到模塊獨立、 功能集中的目的。 模塊內聚的主要類型有:功能內聚、信息內聚、通信內聚、過程內聚、時間內聚、邏輯內 聚和偶然內聚,如下圖 所示。其中,功能內聚和信息內聚屬於高內聚,通信內聚和過程內聚 屬於中等程度的內聚,時間內聚、邏輯內聚和偶然內聚則屬於低內聚;而且,模塊內聚程度越 高,其功能越集中、獨立性越強。
內聚所體現的是模塊的內部功能構造,耦合所體現的是模塊之間的聯系。一般情況下,內 聚和耦合是相互關聯的,模塊的內聚程度越高,則模塊間的耦合程度就會越低,但這也不是絕 對的。值得指出的是,比起模塊之間的耦合來,模塊的內聚更顯重要。因此,實際設計中應當 把更多的注意力放在如何提高模塊的內聚程度上。 模塊內聚的提高依賴於對模塊功能的正確認識,應該通過定義使每一個模塊都具有明確的 功能。為了更好地認識模塊內聚,下面將對上述幾種內聚類型分別加以說明。
a.偶然內聚
當模塊內各部分之間沒有聯系,或即使有聯系,這種聯系也很松散時,將會出現偶然內聚。偶然內聚往往產生於對程序的錯誤認識或沒有進行軟件結構設計就直接編程。例如,一些 編程人員可能會將一些沒有實質聯系,但在程序中重復多次出現的語句抽出來,組成一個新的 模塊,這樣的模塊就是偶然內聚模塊。 偶然內聚模塊由於是隨意拼湊而成,模塊內聚程度最低、功能模糊,很難進行維護。
b.邏輯內聚
邏輯內聚是把幾種相關的功能組合在一起形成為一個模塊。在調用邏輯內聚模塊時,可以 由傳送給模塊的判定參數來確定該模塊應執行哪一種功能。例如下圖 中的打印模塊。 邏輯內聚模塊比偶然內聚模塊的內聚程度要高,因為它表明了各部分之間在功能上的相關 關系。但是它每次執行的不是一種功能,而是若干功能中的一種,因此它不易修改。另外,在 調用邏輯內聚模塊時,需要進行控制參數的傳遞,由此增加了模塊間的耦合。
c.時間內聚
時間內聚模塊一般是多功能模塊,其特點是模塊中的各項功能的執行與時間有關,通常要 求所有功能必須在同一時間段內執行。例如初始化模塊,其功能可能包括給變量賦初值、連接 數據源、打開數據表、打開文件等,這些操作要求在程序開始執行的最初一段時間內全部完成。
時間內聚模塊比邏輯內聚模塊的內聚程度又稍高一些,其內部邏輯比較簡單,一般不需要 進行判定轉移。
d.過程內聚
如果一個模塊內的處理是相關的,而且必須以特定次序執行,則稱之為過程內聚模塊。在 使用流程圖設計程序的時侯,常常通過流程圖來確定模塊划分,由此得到的就往往是過程內聚 模塊。例如,可以根據流程圖中的循環部分、判定部分和計算部分將程序分成三個模塊,這三 個模塊就是過程內聚模塊。 過程內聚模塊的內聚程度比時間內聚模塊的內聚程度更強一些,但過程內聚模塊僅包括完 整功能的一部分,因此模塊之間的耦合程度比較高。
e.通信內聚
如果一個模塊內各功能部分都使用了相同的輸入數據或產生了相同的輸出數據,則稱之為 通信內聚模塊。例如下圖 中的處理工資模塊。 通信內聚模塊由一些獨立的功能組成,因此其內聚程度比過程內聚程度要高。
f.順序內聚
如果一個模塊內的諸多功能元素都和某一個功能元素密切相關,而且這些功能元素必須順 序安排(前一項功能的數據輸出作為后一項功能的數據輸入),則稱之為順序內聚模塊。當根據 數據流圖划分模塊時,由此得到的通常就是順序內聚模塊。例如下圖 中的入庫統計模塊。 順序內聚模塊也包含着多項功能,但它有一個核心功能,其他功能則圍繞着這個核心而安 排。因此,順序內聚程度比通信內聚程度更高。
g.功能內聚
如果一個模塊中各個部分都是完成某一具體功能必不可少的組成部分,各個部分協同工 作、緊密聯系、不可分割,則稱該模塊為功能內聚模塊。 功能內聚模塊的特征是功能單一、接口簡單,因此其容易實現、便於維護。與其他內聚類 型相比,功能內聚具有最高的內聚程度,軟件結構設計時應以其作為追求目標。
結構化設計建模
軟件結構設計涉及模塊功能、模塊接口與模塊調用關系等問題,為了使這些問題能夠集中 清晰地表達出來,軟件結構設計需要借助於一定的圖形工具來建立設計模型,例如軟件結構圖、 HIPO 圖。
軟件結構圖
軟件結構圖由 Yourdon 於 20 世紀 70 年代提出,並被廣泛應用於軟件結構設計中,能夠有 效說明軟件中模塊之間的調用與通信。 軟件結構圖使用矩形框表示模塊(框內注明模塊的名字或主要功能),使用帶箭頭的直線 段連接上下級模塊,以表示上級模塊對下級模塊的調用。此外,軟件結構圖還可以在調用箭頭 旁使用帶注釋的箭頭,以表示上級模塊在調用下級模塊時參數的傳遞與結果的返回,其基本圖 形符號如下表 所列。
上圖圖是一個自動閱卷系統的軟件結構圖。閱卷總控模塊為頂層模塊,其調用考卷數據 輸入、閱卷處理和考卷成績輸出這三個模塊,以進行考卷輸入、成績計算和成績輸出的控制。 在更下一級模塊調用中,考卷數據輸入模塊通過調用讀答卷卡模塊將考卷原始數據輸入,然后 調用檢驗考卷數據模塊產生出適合評分計算的有效數據;考卷成績輸出模塊則通過調用格式化 成績數據模塊對計算出的成績數據進行輸出前的格式化處理,然后調用寫成績記錄模塊實現成 績的存檔操作。
HIPO 圖
HIPO 圖是美國 IBM 公司推出的“H 圖”與“IPO 圖”的組合。
a.H 圖
H 圖是軟件層次圖的簡稱,用於描述軟件結構上的分層調用關系,作用類似於軟件結構圖, 但不涉及調用時的數據流、控制流等附加信息。 H 圖的優點是清晰度高,能夠用於正式文檔中對軟件結構的描述。圖 5-21 是自動閱卷系統 的 H 圖,可以看出,它比上面的軟件結構圖要清晰得多。 為了能使 H 圖中的模塊具有可追蹤性,由此可以與它所對應的 IPO 圖聯系起來。圖中模塊 除了最頂層的之外,其他的模塊都需要按照一定的規則編號,以方便檢索。
b.IPO圖
IPO 圖是“輸入—處理—輸出圖”的簡稱,其中的“I”是指輸入,“O”是指輸出,“P” 是指處理。可以使用 IPO 圖對模塊進行外部特征描述,涉及輸入、輸出接口和基本加工步驟等。 在 HIPO 圖中,需要針對 H 圖中的每個模塊給出 IPO 圖描述。
從上面的 IPO 圖舉例可以看到,IPO 圖提供了有關模塊的更加完整的定義和說明。顯然, 這將有利於由概要設計到詳細設計的過渡。
軟件結構優化
軟件結構設計往往需要經歷多次反復,其作用是可以不斷地改進軟件結構,提高軟件質量。 為了改進軟件結構,軟件設計人員進行了長期的實踐與總結,由此得到了一些優化設計的原則。 本節將介紹這些原則。
使模塊功能完整
一個完整的功能模塊,不僅能夠完成指定的功能,而且還應當能夠將完成任務的狀態通知 使用者。 具體說來,一個完整的功能模塊應當包含以下幾個部分的內容:
a.執行規定功能的部分。
b.出錯處理的部分。當模塊不能完成規定的功能時,必須回送出錯標志,並向它的調用 者報告出現這種例外情況的原因。
c.如果需要返回一系列數據給它的調用者,在完成數據加工時,應當給它的調用者返回 一個該模塊執行是否正確結束的“標志”。
使模塊大小適中
許多情況下,可以用模塊中所含語句的數量的多少來衡量模塊的大小。有人認為限制模塊 的大小也是減少模塊復雜性的有效手段之一,因而要求把模塊的大小限制在一定的范圍之內, 例如將模塊內的語句限制在 50~100 行左右。當然,這只能作為參考。 一般說來,模塊過大的原因往往是模塊的功能太多,因此有必要對大模塊做進一步的分解。 大多數情況下,可以從大模塊中分解出一些下級模塊或同層模塊。 軟件結構設計時,也有可能出現模塊過小的問題。如果模塊太小,則要注意這個模塊的功 能是否完整,是否將一個完整的功能分解到多個模塊中去了。許多情況下,可以考慮將較小的 模塊與調用它的上級模塊合並。如果模塊雖小但功能內聚性好,或者它為多個模塊所共享,或 者調用它的上級模塊很復雜,則不要貿然將小模塊與其他模塊合並,而是需要做更加細致的分析。
使模塊功能可預測
一個功能可預測的模塊可以被看成是一個“黑箱”,無論內部處理細節如何,只要輸入數 據是相同的,就總能產生相同的輸出結果。 例如,在模塊中使用了靜態變量。因為靜態變量會在模塊內部產生較難預見的存儲,而如 果這個靜態變量又被用為多項功能的選擇標記,則可能會使得模塊的功能難以被調用者預知。 由於這個原因,設計者要特別慎重地使用靜態變量。 模塊功能可預測還意味着,模塊的功能必須明確清晰地定義,應該使模塊具有很好的內 聚性。
(4)盡量降低模塊接口的復雜程度
模塊接口是模塊與外界進行通信的通道,較復雜的接口往往會帶來較高的耦合。因此,應 努力降低模塊接口的復雜程度。對此,可以從以下兩個方面作出考慮。
a.接口參數盡量采用簡單數據類型,以使接口容易理解。例如,盡量使用基本字符、整 數類型,而不是數組、指針、結合體類型。
b.限制接口參數的個數。接口參數個數太多,往往是由於模塊功能混雜,不得不依靠參 數進行調控。因此,過多的參數往往意味着模塊還有進一步分解的必要。
使模塊作用范圍限制在其控制范圍之內
模塊的控制范圍包括它本身及其所有從屬於它的直接或間接下級模塊。如圖 5-24 所示, 模塊 B 的控制范圍是模塊 E、F、G、K,模塊 C 的控制范圍是模塊 H、I、L、K,模塊 D 的控制范 圍是模塊 I、J、L。 模塊的作用范圍則是指模塊內一個判定的影響范圍,凡是受這個判定影響的所有模塊都屬 於這個判定的作用范圍。其中,如果一個判定的作用范圍包含在這個判定所在模塊的控制范圍 之內,則這種結構是簡單的;否則,其結構就是不簡單的,需要進行結構調整。 例如,圖 5-24 中的模塊 F。如果它做出一個判定之后,接着需要模塊 G 工作,由於模塊 G 不在模塊 F 控制范圍之內,因此模塊 F 必須返回一個信號給模塊 B,再由 B 把信號傳送給模塊 G。 顯然這不是一個好的設計,它增加了模塊之間數據的傳送量,並使模塊之間出現了控制耦合, 因此需要對其結構進行調整。
在設計過程中,如果發現模塊的作用范圍不在控制范圍之內時,可以采用如下辦法進行結 構調整,把模塊的作用范圍移到其控制范圍之內。
(1)將判定所在的模塊合並到它的父模塊中去,或上移到層次較高的位置上去,由此可使 判定處於一個較高的位置,以達到有效的控制。例如,將模塊 F 與模塊 B 合並,如圖 5-25 所示, 由此可使模塊 G 受到控制。
(2)將受判定影響的模塊下移到控制范圍以內。例如,將模塊 G 下移到模塊 F 之下,如圖 5-26 所示,由此可使模塊 G 受到模塊 F 控制。 需要注意的是:在改進模塊的結構時,應當根據具體情況通盤考慮,既要盡量小范圍地調 整結構,使改進后的軟件結構能夠最好地體現問題的原來結構,又要考慮改進后的結構在實現 上的可行性。
深度、寬度、扇出和扇入應當適當
軟件的深度是指軟件結構的層數。例如,圖 5-24 中的軟件結構,其深度為 4 層。
軟件的寬度是指軟件結構同一個層次上模塊的總個數的最大值。例如,圖 5-24 中的軟件 結構,其第二層寬度是 3,第三層寬度是 6,第四層寬度是 2。其整個軟件的寬度是 6。 軟件結構上的深度、寬度,在一定程度上反映出了軟件系統的規模和復雜程度。也就是說, 軟件規模越大越復雜,其深度、寬度也會越大。一般說來,深度、寬度會受模塊的扇出、扇入 影響,並應該有一個合適的大小。深度、寬度太小,往往表示模塊分解得還不夠細,需要進一 步分解。而深度、寬度太大,則可能表示模塊分解得太細小了,或功能冗余模塊太多了,以致 軟件結構變得復雜起來。一般說來,軟件結構越復雜,模塊之間的耦合就會越大。因此,假如 軟件結構過於復雜,就有必要將一些模塊進行適當的合並,將那些功能相同或相似的模塊合並 起來作為公共模塊使用。 模塊的扇出是指模塊直接調用的下級模塊的個數。比較適當的扇出數為 2~5,一般不要超 過 9。如果一個模塊的扇出過大,就表明該模塊具有過分復雜的控制功能,需要協調和控制過 多的下屬模塊。對此,應當適當增加中間層次的控制模塊,將比較集中的控制分解開來,如圖 5-27 所示。但扇出過小也不好,這樣將使得軟件結構的深度大大增加,會帶來過多的調用和返 回的時間開銷,由此降低軟件的工作效率。
模塊的扇入是指模塊受到了多少個直接上級模塊的調用。一個模塊的扇入越大,則共享該 模塊的上級模塊的數目就越多。如果一個模塊的扇入數太大,而它又不是公用模塊,則說明該 模塊可能具有多項功能。在這種情況下,應當對它做進一步的分析,並將其功能做進一步的分解。
一般說來,各個不同層次的模塊具有以下特點:頂層模塊起全局控制作用;中間層次的模 塊起局部控制作用,並適當承擔一些簡單的操作提示功能;底層模塊擔任具體加工任務。因此, 一個設計得比較好的軟件結構通常應具有這樣的特征:頂層模塊高扇出,中層模塊低扇出,底 層模塊高扇入。