iT邦幫忙

2022 iThome 鐵人賽

DAY 15
2
自我挑戰組

【從工程師升級成為資深工程師的那檔事】 系列 第 15

【從工程師升級成為資深工程師的那檔事Day 15】設計模式 - 橋接模式 & 策略模式

  • 分享至 

  • xImage
  •  

在GOF 23種設計模式中,橋接模式屬於結構型而策略模式屬於行為型的設計模式。
雖然在定義及用途上有些許不同,但設計上的架構有著相似之處。

橋接模式 Bridge Pattern

定義

抽象部分與它的具體實現部分分離,使它們都可以獨立地變化。

看著這個定義,我相信十有八九的人應該是都會放棄這個模式了,
所以我們這邊就簡單地用自己的語言幫她翻譯一下:
** 透過使用傳入內部的物件(Object)來完成方法(Method)的內容 **

用途

對於橋接模式用途的解釋是:
可以用不同的工具,來完成一樣的結果。
最常見的例子像是兼容不同的資料庫的資料索取,或是跨平台的畫面渲染...等。

策略模式 Strategy Pattern

定義

將一系列的算法封裝起來,並且在運行時可以替換使用。

實作上的概念其實也跟前面一樣:
** 透過使用傳入內部的物件(Object)來完成方法(Method)的內容 **
(不一樣的地方最後在解釋)

用途

策略模式主要是解決,在同一個流程下,不同條件所產生的變化
例如:遊戲中技能傷害的計算方式(戰士與法師....等各職業的算法不同),
或是公司內部KPI對於薪資的影響(工程師、專案經理...等職位的算法不同)。

橋接模式 與 策略模式

與其說一大堆理論,不如看個幾行程式碼...

範例

假設今天我們有兩個需求

  1. 需要將員工的KPI資料撈出來,但因為公司內部還未將資料正規化。
    所以經理的資料在資料庫內,工程師則是.txt的文件

  2. 用剛剛取得的KPI計算公司員工的薪水,依照不同的職位來計算:

    • 工程師 50000 + 5000 * KPI
    • 主管 20000 + 10000 * KPI

這樣的問題我們應該如何設計呢?

//定義 員工資訊的介面
interface IStaffInfo{
    public string selectName();
    public string selectTitle();
    public int selectKPI();
}

//分別實作用 DB 及 TxT 方式取得員工資訊的物件
class DBStaffInfo : IStaffInfo{
    
    public string selectName(){
    string name ;
    //TODO: ...從資料庫取得職員 姓名...
    return name ;
    }
    public string selectTitle(){
        string title ;
        //TODO: ...從資料庫取得職員 職稱...
        return title ;
    }
    public int selectKPI(){
        string KPI ;
        //TODO: ...從資料庫取得職員 績效...
        return KPI ;
    }


}

class TxtStaffInfo : IStaffInfo{
    
    public string selectName(){
    string name ;
    //TODO: ...從文件檔取得職員 姓名...
    return name ;
    }
    public string selectTitle(){
        string title ;
        //TODO: ...從文件檔取得職員 職稱...
        return title ;
    }
    public int selectKPI(){
        string KPI ;
        //TODO: ...從文件檔取得職員 績效...
        return KPI ;
    }


}


//定義好需求上的 員工抽象類別
abstract class AbstractStaff{

    private IStaffInfo info;
    //職員 名稱
    public abstract string getName();
    //職員 職稱
    public abstract string getTitle();
    //職員 績效
    public abstract int getKPI();

}

//實作員工類別
abstract class Staff : AbstractStaff{
    private IStaffInfo info;
    private string name ;
    private string title;
    private int KPI;
    
    //傳入基本資料
    public Staff(IStaffInfo info){
        this.info = info;
    }
    
    //從info中取得 職員名稱 的資料
    public string getName(){
        name = info.selectName();
        return name;
    }
    //從info中取得 職員職位 的資料
    public string getTitle(){
        title = info.selectTitle();
        return title;
    }
    //從info中取得 職員績效 的資料
    public int getKPI(){
        KPI = info.selectKPI();
        return KPI;
    }

}

我們接著設計員工薪資的計算方式

//定義好介面
interface ICalculateSalaryStrategy{
    public int calculate(int KPI);
}
//主管 的薪資計算策略
class ManagerCalculateStrategy{
    public int calculate(int KPI){
        return 20000 + 10000 * KPI;
    }
}
//工程師 的薪資計算策略
class EngineerCalculateStrategy{
    public int calculate(int KPI){
        return 50000 + 5000 * KPI;
    }
}

最後我們來看看主流程main()的部分:

public static void main(){
    //----- 橋接模式 -----
    
    IStaffInfo db_info = new DBStaffInfo();
    IStaffInfo txt_info = new TxtStaffInfo();
    //新增兩個員工
    //並分別透過 DB、Txt兩種方式取得資料
    AbstractStaff manager = new Staff(db_info);
    AbstractStaff engineer = new Staff(txt_info);
    
    // ================
    
    //----- 策略模式 -----
    ICalculateSalaryStrategy calculate;
    
    //判斷應該要用何種方式計算薪水
    if (manager.getTitle() == 'manager'){
        calculate = new ManagerCalculateStrategy();
    }
    else if(manager.getTitle() == 'engineer'){
        calculate = new EngineerCalculateStrategy();
    }
    
    //計算主管的薪水
    calculate.calculate(KPI);
    
    
}

區別

橋接模式: 在同一個結構下用不同的工具,也要有相同的輸出 (不管用DB、TXT都要得到員工資料)
策略模式: 在同一個流程下用不同的方法,得到不同的答案 (同樣都是計算薪水,但是希望有不同的計算方式)

橋接模式: 通常會負責處理執行以前的變因(資料取得要從DB 還是 Txt開始執行以前就知道了)
策略模式: 通常處理執行以後才會發生的變因(要執行哪一種策略要在流程中有對應條件的時候才知道)

橋接模式: 在結構上將下層的工具類與上層的應用分開(取得職員資料 與 使用職員資料 分開)
策略模式: 將下層選擇性結構轉到上層處理,保持下層處理業務上層處理流程(calculate負責計算、main負責決定用甚麼方法 )

結語

個人認為這兩種模式在本質上是一樣的。
所以在學習的過程中,不必過於區分兩者的區別。
只需要了解在這樣的設計架構底下有甚麼樣的應用情境。

其實,還有一種設計模式(狀態模式)也與這兩者很類似,
不過這個設計模式我們就留到之後的章節再說。


上一篇
【從工程師升級成為資深工程師的那檔事Day 14】設計模式 - 適配器模式
下一篇
【從工程師升級成為資深工程師的那檔事Day 16】設計模式 - 裝飾器模式
系列文
【從工程師升級成為資深工程師的那檔事】 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言