網頁

2016年1月6日 星期三

類別或模組關係

塑模概論

模組設計理想特徵:

1.          友善分割的:模組分割大小適中
2.          單一責任的:模組只處理單一領域的問題
3.          有功能的:可提供功能
4.          有效率的:執行時間少
5.          經濟的:運作成本低
6.          可靠的:不易故障
7.          安全的:能抵抗未授權使用、外部攻擊
8.          有彈性的:可處理不同狀況
9.          可攜性的:可移植至不同平台
10.      構造簡單的:內部構造簡單易懂
11.      可管理的:可衡量、檢測模組特性
12.      低耦合的:與其他模組關聯稀疏
13.      高聚合:模組內部功能關聯緊密
14.      易用性的:使用方式簡單、舒適
15.      可重複利用的:同模組可以多次使用
16.      穩定的:模組不會任意變化


內聚力與耦合力

可接受的設計

內聚力:功能內聚力、順序內聚力、溝通內聚力
耦合力:無耦合、訊息耦合、資料耦合力、資料結構耦合力。
理想設計:高內聚力,鬆散耦合。功能內聚力、無耦合力

內聚力(Cohesion)

內聚力:衡量模組內部之功能相關的程度。
最理想:功能內聚性
好的:聯絡內聚性、順序內聚性
不好的:偶然內聚性、邏輯內聚性

內聚力分為七種:(強至弱)
1.          功能內聚力(Functional Cohesion)
一個模組只做一件事情,具有唯一的功能。

2.          順序內聚力(Sequential Cohesion)
模組內具有多個功能,且一項功能的輸出為下一個功能的輸入,共用相同資料

3.          溝通內聚力(Communication Cohesion)
模組內有多個功能,且各功能共用相同的資料,無順序

4.          程序內聚力(Procedural Cohesion)
模組內有多個功能,這有執行順序來,不共用資料,功能群集在一模組內以確保執行順序

5.          暫時內聚力(Temporal Cohesion)
模組內有多個功能,無順序,不共用資料,但是僅在時序上關聯,須在同一時間內執行

6.          邏輯內聚力(Logical Cohesion)
指模組內具有多個邏輯關聯的功能

7.          偶發內聚力(Coincidental Cohesion)
模組內有多個功能,且每一件功能都不相干,在設計時盡量避免

耦合力(Coupling)

耦合力:衡量模組間相互關聯的強度。
若兩模組間有多種耦合關係,以較強的耦合力為準
低耦合性稱鬆散耦合,高耦合性稱緊密耦合
連鎖反應:解決一模組內的錯誤時,引起其他模組內新的錯誤
解決方法:讓每個模組盡量的獨立,減少耦合力。

1.          無耦合
模組完全不和其他模組交換資訊

2.          訊息耦合(message coupling,是無耦合之外,耦合度最低的耦合)
各模組均為獨立互不干擾,可透過公共介面來提供服務。此介面為抽象介面,不因特定模組修改,而使介面有所變動。即若A模組使用到B模組的服務,不會因為B模組的服務修改而連帶到A模組。

3.          資料耦合力(Data Coupling)
模組間使用簡單資料型別(int, float, char)作為傳遞之參數

4.          資料結構耦合力(Stamp Coupling) 特徵耦合
模組間以資料結構型別(struct) 作為傳遞之參數
問題:
可能只用到結構型別中局部的欄位,比實際需要更多的記憶體空間
資料結構內欄位修改過,則相關模組均受影響

5.          控制耦合力(Control Coupling)
模組傳遞旗標去控制另一模組內的邏輯流程
問題:
不瞭解被呼叫的模組,不易撰寫程式,增加程式測試成本

6.          外部耦合(external coupling
二個模組共用一個外加的資料格式、通訊協定或是裝置介面

7.          共同耦合力(Common Coupling) 全局耦合(global coupling.
兩模組使用相同的資料區(全局變數),且都可讀寫資料區內之資料
少用,主要原因為:
資料錯誤,涉及之模組均受影響。
使用共同資料區的模組名稱均模稜兩可,不易定義
資料常被濫用,使模組邏輯變得複雜
維護上困難。

8.          內容耦合力(Content Coupling) 病態耦合(pathological coupling
一模組使用另一模組內之部分程式碼或改變其他模組內的局部變數。指一模組依賴另一模組的內部作業

模組的耦合性公式

對於資料和控制流的耦合:
di:輸入資料參數的個數
ci:輸入控制參數的個數
do:輸出資料參數的個數
co:輸出控制參數的個數
全域耦合:
gd:用來儲存資料的全域變數
gc:用來控制的全域變數
環境耦合:
w:此模組呼叫的模組個數(扇出)
r:呼叫此模組的模組個數(扇入)
\mathrm{Coupling}(C) = 1 - \frac{1}{d_{i} + 2\times c_{i} + d_{o} + 2\times c_{o} + g_{d} + 2\times g_{c} + r + w}

物件導向設計

類別間耦合關係


l   子類別耦合(subclass coupling
描述子類別和父類別之間的關係,子類別連結到父類別,但父類別沒有連結到子類別。

l   時空耦合(temporal coupling
二個動作只因為同時間發生,就被包裝在一個模組中。

l   互動耦合(interaction coupling)
兩類別間用來傳送訊息的類型數目。

l   元件耦合(component coupling)
類別使用或參考到的外部類別程度。

l   繼承耦合(inheritance coupling)
子類別不需要父類別特性的程度

l   操作內聚力(operation cohesion)
類別內單一方法為單一功能性

l   類別內聚力(class cohesion)
類別內容為單一責任性

l   專門內聚力(specialization cohesion)
類別繼承合乎父類別的語意


UML類圖中,有六種類別關系(耦合強度由強至弱排序)
1.          泛化(Generalization
是一種繼承關系,表示一般與特殊的關系,它指定了子類如何特化父類的所有特征和行爲。
表示法:空心三角箭頭的實線,箭頭指向父類

2.          實現(Realization
是一種類別與介面的關系,表示類別實現介面的所有特性和行爲
表示法:空心三角箭頭的虛線,箭頭指向介面

3.          組合(Composition)
整體與部分的關系,但部分不能離開整體而單獨存在
表示法:實心菱形的實線,菱形指向整體

4.          聚合(Aggregation
整體與部分的關系,且部分可以離開整體而單獨存在。
表示法:空心菱形的實心線,菱形指向整體

5.          關聯(Association)
一類別知道或擁有另一個類別的存在,分雙向、單向。
表示法:單向關聯普通箭頭的實心線,指向被擁有者;雙向關聯可以有兩個箭頭或者沒有箭頭。

6.          依賴(Dependency)
一種使用的關系,即一個類的實現需要另一個類別的協助,盡量不使用雙向的互相依賴
表示法:帶箭頭的虛線,指向被使用者

設計原則

目的是設計出易維護、易擴展、易重用、靈活性加的程式。
一個好的程式,必須滿足以下條件:
l   可以正常運作(沒有bug)
l   程式碼夠短(技巧好)
l   程式碼容易理解(易改寫)
l   可以重複利用(降低開發成本)
l   能幫上使用者(方便好用)

1.          開閉原則(Open-Closed Principle,OCP)
「一個類別、模組、元件、函式應該開放擴充,而關閉修改。」
重構(refactoring)例外

2.          Liskov替換原則(The Liskov Substitution Principle, LSP)
「子類別必須是加強父類別的功能,不能減少。」
父類別能出現的地方,子類別就可以出現,而且替換成子類別不會造成錯誤或異常。

3.          相依倒轉原則(Dependency Inversion Principle, DIP)
「依賴抽象化,而不要依賴具體化。」
又譯依賴倒置原則、顛覆依賴原則、相依性注入或反轉原則

4.          介面隔離原則(Interface Segregation Principle, ISP)
「不依賴在不需要的介面,用多個專門介面取代單一的總合介面。」
又叫介面分離原則

5.          單一職責原則(Single Responsibility Principle, SRP)
「一個類別應該只具有一個責原。」
不要將不同的職責工作封裝在一起,而應該隔離。

6.          極少化原則(Least Knowledge Principle, LKP)
「一個物件應該對其他物件有最少的相互作用。」
又叫最小知識原則、迪米特法則(Law of Demeter)
盡可能少的和其他軟體實體發生相互作用

7.          合成/聚合複用原則 (CARP,Composite/Aggregate Reuse Principle)
「少繼承、多聚合。」

8.          不要自我重覆(DRY,Don't Repeat Yourself)
「不要寫出重覆的功能」
適用在相同的功能而不是相似的程式

9.          將變動封裝起來(Encapsulate Changes)
「用戶端不因物件內部變化,而有異動」
封裝將細節隱藏起來,只提供主要介面供使用者驅動,若內部實作細節有任何異動,用戶端可以不用做任何異動

10.      委派原則(Delegation Principle)
「把責任委派給該負責的類別。」
不要試著在一個類別中做所有的事

11.      針對介面而非實作(Programming for Interface not implementation)
「針對介面、而非針對實作來撰寫程式。」
善用 polymorphism,利用 super-type來當作觀察實際變數的窗口,不要把真實 runtime object 寫死在 code 裡面。多用同名異式(Polymorphism)=多型=動態繫結(Dynamic binding)、控制反轉(Inversion of Control,IoC

12.      發行可重複使用等效原則(The Release Reuse Equivalency Principle, REP)
「模組可支援與維護較舊的版本。」

13.      共同封閉原則(The Common Closure Principle, CCP)
「同屬一個群組的類別改變,不影響其他群組的類別。」

14.      共同可重複使用原則(The Common Reuse Principle, CRP)
「不能一起被重複使用的類別,不應該群聚在一起。」

最少承諾原則(principle of least commitment)
「物件的介面僅提供其基本行為之描述,除此之外再沒別的,」

1 則留言:

  1. 明確的規劃跟制度,更勝於那吹毛求疵的效能。

    回覆刪除