0%

SOLID 筆記 - (2)內聚力與耦合力

1. 何謂”模組” (Module)

  • 一種抽象的概念

  • 其實C#沒有Module概念

  • 以C#舉例

    • 可能是一個「類別」(class)
    • 可能是一個「方法」(method)
    • 可能是一個「組件」(assembly)

2. 內聚力 Cohesion

  • 在一個”模組” 內完成 “一件工作” 的度量指標
  • 內聚一次只專注做一件事

2.1. 高內聚力

  • 在一個”模組”內只完成一件工作
  • 內聚力高,意味著該模組可以獨立運作,也意味著更容易重複利用
  • 範例:一個class只負責一件事情(例如寄送郵件)

2.2. 低內聚力

  • 在一個”模組”內完成多份工作
  • 內聚力低,意味著這個棤組會造成難以維護/測試/重用/理解
  • 範例:所有功能寫在一個class裡面或一個method有5000行程式碼

2.3. 最佳實務

  • 在設計模組的時候,要盡量設計出高內聚力的程式碼。
  • 若要在一個模組內完成多項工作,建議拆成多個不同的類別
  • 實現SRP就是實現「提高內聚力」的一種表現

3. 耦合力 Coupling

  • 模組與模組之間的關聯強度
    • 模組之間相互依賴的程度
    • 衡量兩個模組的緊密連接程度
    • 範例:在ClassB裡面,直接”建立”了ClassA的物件實體,就會建立ClassA與ClassB之間的”耦合關係”。

3.1. 高耦合力

  • 意著當改了A模組時,相關的B模組就會容易被影響(改A壞B)

3.2. 低耦合力

  • 當在修改模組的時候,有越少的模組被影響,就意味著耦合力較低。

3.3. 最佳實務

  • 在設計不同模組的時候,要盡量設計出低耦合力的程式碼。
  • 實現DIP就是實現「降低耦合力」的一個原則。

3.4. 隨堂測驗

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class InvitationService public

public void SendInvite (string elail, string firstName, string lastName)
{

if (String.IsNullOrWhiteSpace(firstName) || String.IsNullOrWhiteSpace(lastName)){
throw new Exception("Name is not valid!");
}

if (!email.Contains("@") || !email.Contains(".")){
throw new Exception("Email is not valid!!");
}

SmtpClient client = new SmtpClient();

client.Send(new MailMessage("mysite@nowhere.com", email) { Subject "Please join me at my party!" });

}

}

這段代碼中的 InvitationService 類與以下幾個類發生了耦合關係:

  • String 類 - 用於驗證 firstNamelastName 是否為空或空白字串。

    方法:String.IsNullOrWhiteSpace

  • Exception 類 - 用於在驗證失敗時拋出異常。

    1
    2
    throw new Exception("Name is not valid!");
    throw new Exception("Email is not valid!");
  • SmtpClient 類 - 用於發送電子郵件。

    創建了 SmtpClient 實例 client

  • MailMessage 類 - 用於構造電子郵件訊息。

    創建了 MailMessage 物件,設置發件人和收件人資訊以及郵件主題。

3.5. 隨堂測驗

耦合是不可避免的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Order {
private ShoppingCartContents cart;
private float salestax;
public Order(ShoppingCartContents cart, float salesTax) {
this.cart = cart;
this.salesTax = salesTax;
}
public class ShoppingCart {
public float Price;
public int Quantity;
}
public float OrderTotal() {
float cartTotal = 0;
for (int i = 0; i < cart.items.length; i++) {
cartTotal += cart.items[i].Price * cart.items[i].Quantity;
}
cartTotal += cartTotal * salestax;
return cartTotal;
}
}

public class ShoppingCartContents {
public ShoppingCart[] items;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@startuml
class Order {
- ShoppingCartContents cart
- float salestax
+ Order(ShoppingCartContents, float)
+ OrderTotal(): float
}
class ShoppingCartContents {
- ShoppingCart[] items
}
class ShoppingCart {
+ float Price
+ int Quantity
}
Order --> ShoppingCartContents
ShoppingCartContents --> ShoppingCart
@enduml

img