本系列文章同步分享於IT邦幫忙第12屆鐵人賽
Design Pattern 系列文章導讀
Design Pattern可以說是開發上大家都會遇到的一個課題,
這系列文會從Design Principles、各種design pattern到最後的Anti-Patterns & Code Smells介紹下去,讓我們可以更了解各種pattern的使用時機與場合。
預計目標主題如下,若有哪部分不熟的章節可以直接點進去看
註:可以利用Online Java Compiler IDE
註:可以利用Online Java Compiler IDE
-
定義
There should never be more than one reason for a class to change.
翻譯年糕:一個類別只能有一個改變的原因。
什麼叫一個原因?是指一個class只能做一件事嗎? 我們舉一個生活化的例子:購物車!!
當我們在購物,決定要將購物車內容結帳時會經由以下步驟:確認訂單、確認聯絡資料、確認收貨地點、付費。用程式呈現方式如下:
interface IShoppingCart{
void checkOrder();
void checkContactInfo();
void checkPlace();
void paid();
}
class ShoppingCart implements IShoppingCart{
@Override
public void checkOrder(){
System.out.println("請確認訂單");
};
@Override
public void checkContactInfo(){
System.out.println("請聯絡資料");
};
@Override
public void checkPlace(){
System.out.println("請收貨地點");
};
@Override
public void paid(){
System.out.println("請付款");
};
}
public class MyCart {
public static void main(String args[]) {
ShoppingCart cart = new ShoppingCart();
cart.checkOrder();
cart.checkContactInfo();
cart.checkPlace();
cart.paid();
}
}
output
請確認訂單
請聯絡資料
請收貨地點
請付款
這是我們在購物會經過的流程。可以發現,shoppingCart內包含了兩個職責,確認資料
以及付費
。確認訂單、確認聯絡資料與確認收貨地點都是在檢查這筆訂單的資訊是否正確。而付費則是繳清這筆訂單所需的金額,很明顯地與其他三者的職責不同。若購物車需要有更多元的付費方法,比方說加入電子支付,又或是確認資料的功能要做更改,都會需要更動到整個interface,這樣可能會影響到其他不需要更動的功能。
-
使用 Single Responsibility Principle
一開始我們提到 一個類別只能有一個改變的原因。
,也就是說我們只希望這個interface只因為一個原因(例如:異動付款相關功能)才做異動,所以我們就將這兩個職責劃分成兩類:
public interface CheckData{
void checkOrder();
void checkContactInfo();
void checkPlace();
}
public interface Payment{
void paid();
}
public class ShoppingCart implements CheckData, Payment{
@Override
public void checkOrder(){
System.out.println("請確認訂單");
};
@Override
public void checkContactInfo(){
System.out.println("請聯絡資料");
};
@Override
public void checkPlace(){
System.out.println("請收貨地點");
};
@Override
public void paid(){
System.out.println("請付款");
};
}
public class MyCart {
public static void main(String args[]) {
ShoppingCart cart = new ShoppingCart();
cart.checkOrder();
cart.checkContactInfo();
cart.checkPlace();
cart.paid();
}
}
這樣的設計就達到了一個interface只有一個職責的原則。需要增加付款方式就改動Payment,需要更改確認資料內容就更改CheckData。如此一來就符合SRP的目標一個類別只能有一個改變的原因。
SRP與ISP的差異
看完這SRP與IRP兩篇的人可能會覺得,SRP跟IRP不都是拆分interface嗎?那有什麼不同?
SRP的目的在於一個模組只能有承擔一個責任。
ISP的目的在於不強迫實作的類別實作不需要的function。
我們可以用不同的角度去看這件事。
SRP注重的是設計層面,如何劃分功能的歸類,讓程式方便維護及擴充。
ISP則是注重在客戶端層面,認為只需要呈現客戶端所需要的功能即可。
-
小結
-
SRP的目的:
實現高內聚,將不相關的程式碼移除,使得整體程式碼中的每個部分都與自己實作的功能相關。
-
SRP的優缺點比較
優點 | 缺點 |
---|---|
- 降低類別複雜度。- 提高可讀性及維護性。- 變更引起的風險降低。 | - 功能類別的歸類困難,依照不同情境有不同的劃分方法。 |
-
範例程式碼
範例1:未使用SRP
範例2:使用SRP
-
References
- 設計模式五大基本原則 SOLID
- [Design Pattern] 單一職責原則 (Single Responsibility Principle)