iT邦幫忙

2022 iThome 鐵人賽

DAY 11
1
自我挑戰組

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

【從工程師升級成為資深工程師的那檔事Day 11】設計模式 - 生成器模式

  • 分享至 

  • xImage
  •  

一開始在做開發的時候,可能會因為專案小,
或是時間上的因素使用工廠模式(或是不使用任何的設計模式)來撰寫程式。
但常常會發現經過開發週期不斷的迭代(或是用戶需求的改變),
創建的模式變的不再那麼的單純,
導致原先設計的創見模型變得不再那麼的好使。
這時可能會考慮另一種模式來幫我們解決問題-生成器模式。

生成器模式 Builder Pattern

定義

將實例化的過程抽象化,再透過不同實作方式來完成不同屬性的物件(Object)

用途

在決定是否使用生成器模式之前,可以用兩個原則來思考:

  1. 創建甚麼?(影響產生物件的變因)
  2. 怎麼創建?(創建的步驟)

在開發上若同時遇到這兩個問題的時候,就可以考慮使用這種設計模式。
像是建立遊戲角色的時候,同時就要考慮創建甚麼角色(可能是不同職位、種族之類的問題),
也要考慮怎麼創建這隻角色(能力值、外觀...等對角色的影響)。
或是...
公司的表單簽核系統要考慮創建甚麼畫面(可能是職位或權限對一些欄位的影響),
也要考慮要有哪些欄位(可能是採購的產品、價位...等)

範例

假設我們需要做一個採購單畫面,畫面上有採購項目、商品價格、是否同意採購 3個欄位:

  1. 如果是申請者來看只能填寫項目名稱
  2. 如果是採購人員來看只能填寫商品價格

這時候我們要怎麼設計呢?

//建立一個生成器的抽象類別
abstract class AbstractViewBuilder{
    private Component name;
    private Component price;
    private Component isPassed;

    public AbstractViewBuilder setItemName(string name);
    public AbstractViewBuilder setItemPrice(int price);
    public AbstractViewBuilder setIsPassed(bool isPassed);

    //TODO: 將上面這些元件組成一個畫面
    public Page build{...}

}

//建立實作AbstractViewBuilder 的類別 ApplicantViewBuilder 、ProcurementStaffViewBuilder
class ApplicantViewBuilder : AbstractViewBuilder{
    
    //回傳一個TextBox:Component 讓使用者可以填寫
    public AbstractViewBuilder setItemName(string name){
        TextBox com = new TextBox();
        //TODO:做一些處理
        this.name = com;
        return this;
    }
    //回傳一個Lable:Component 不讓使用者填寫
    public AbstractViewBuilder setItemPrice(int Price){
        Lable com = new Lable();
        //TODO:做一些處理
        this.price = com;
        return this;
    }
    //回傳一個Lable:Component 不讓使用者填寫
    public AbstractViewBuilder setIsPassed(){
        Lable com = new Lable();
        //TODO:做一些處理
        this.isPassed = com;
        return this;
    }
}

class ProcurementStaffViewBuilder : AbstractViewBuilder{
    
    //回傳一個Lable:Component 讓使用者可以填寫
    public AbstractViewBuilder setItemName(string name){
        Lable com = new Lable();
        //TODO:做一些處理
        this.name = com;
        return this;
    }
    //回傳一個TextBox:Component 不讓使用者填寫
    public AbstractViewBuilder setItemPrice(int Price){
        TextBox com = new TextBox();
        //TODO:做一些處理
        this.price = com;
        return this;
    }
    //回傳一個Lable:Component 不讓使用者填寫
    public AbstractViewBuilder setIsPassed(){
        Lable com = new Lable();
        //TODO:做一些處理
        this.isPassed = com;
        return this;
    }
}

//建立Diractor類別
class Diractor{
    public Page createView(AbstractViewBuilder builder){
        //建立頁面
        builder.setItemName("")
            .setItemPrice(0)
            .setIsPassed(false);
        return builder.build();
    }
}

static void main(){
    bool isApplicant = true;
    bool isProcurementStaff = false;
    var diractor = new Diractor();
    //判斷是哪一個職員進入畫面
    AbstractViewBuilder builder = null;
    if(isApplicant){
        builder = new ApplicantViewBuilder();
    }
    else if (isProcurementStaff){
        builder = new ProcurementStaffViewBuilder();
    }
    //這樣就建立完成一個頁面了
    diractor.createView(build);
    
}

結語

這樣的撰寫方式,在未來有個新的頁面需求,我們可以很簡單新增一個類別就能完成。

最後這邊可以思考看看兩個問題:

  1. 當經理來看只能填寫是否同意採購要如何設計?
  2. 如果現在需要做一個通知的頁面(沒有是否同意的欄位)應該如何設計?

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

尚未有邦友留言

立即登入留言