iT邦幫忙

2026 iThome 鐵人賽

DAY 14
0

嗨大家午安

創建型的五個 Pattern 都學完了,今天不講故事了,純粹帶著阿柴回頭看這五天走過的路,把 Factory Method、Abstract Factory、Builder、Singleton、Prototype 攤開來聊一聊

先回顧一下這幾天發生了什麼事

阿柴接手柴咖啡系統,一路上遇到的問題其實都不一樣:

  • 菜單要加燕麥拿鐵,if-else 越疊越高 → Factory Method
  • 套餐組合不能兜錯 → Abstract Factory
  • 拿鐵的客製化選項太多,讓建構子疊到看不懂 → Builder
  • 只有一台咖啡機,卻被無限連線使用 → Singleton
  • 20 杯客製化拿鐵,每杯都要重打一次共同參數 → Prototype

對照表

Pattern 核心問題 柴咖啡情境 關鍵手法
Factory Method 產品怎麼生,還需要加新產品 拿鐵、美式、燕麥拿鐵 定義工廠基底類別或介面,由子類別(如 LatteStore)決定並實作 CreateDrink()
Abstract Factory 一組互相搭配、不能混用的產品,要怎麼正確處理 早餐套餐、下午茶套餐 IComboFactory 一次定義多個 CreateXxx(),每個具體工廠只生產同一個家族
Builder 單一物件的建構參數太多、太複雜,一次到位容易傳錯順序 拿鐵客製化選項(size / ice / sugar / milk) LatteBuilder 用 Fluent 風格一步一步 Set,最後 Build()
Singleton 某個資源全域只該有一份,重複建立會搶資源、卡頓 全店只有一台咖啡機的連線 MachineDriver 用 private 建構子 + static Instance,搭配 Lazy<T>
Prototype 建立新物件成本高,或大部分欄位都跟現成的一樣,想直接複製再改一點點 20杯客製化拿鐵共用同一份標準原型 Clone() 搭配 MemberwiseClone(),注意淺拷貝/深拷貝

這五個 Pattern 怎麼分工

Factory Method 常常是 Abstract Factory 的建材

public class BreakfastComboFactory : IComboFactory
{
    public IDrink CreateDrink() => new Americano();
    public ISideItem CreateSide() => new Bagel();
}

public class AfternoonTeaComboFactory : IComboFactory
{
    public IDrink CreateDrink() => new Latte();
    public ISideItem CreateSide() => new Cake();
}

Day 10 的 BreakfastComboFactory 內部就是靠兩個工廠方法(CreateDrink()CreateSide())組成的,Abstract Factory 管的是「這幾個產品要不要綁成一套」,不是取代 Factory Method,而是疊在它上面多管一層「成套關係」

Builder 跟 Factory 系列關心的層次不一樣:Factory Method、Abstract Factory 回答的是「該生出哪一種(或哪一組)產品」

Builder 回答的是「這一個物件,內部細節該怎麼一步步組裝出來」

兩者可以同時出現,比如某個工廠內部要組出一杯複雜的飲料,實作裡一樣可以呼叫 LatteBuilder

public class LatteBuilder
{
    private CupSize _size = CupSize.Medium;           // 預設中杯
    private IceLevel _iceLevel = IceLevel.Normal;     // 預設正常冰
    private SugarLevel _sugarLevel = SugarLevel.Full; // 預設正常甜
    private MilkType _milkType = MilkType.Regular;    // 預設鮮奶

    public LatteBuilder SetSize(CupSize size) { _size = size; return this; }
    public LatteBuilder SetIce(IceLevel iceLevel) { _iceLevel = iceLevel; return this; }
    public LatteBuilder SetSugar(SugarLevel sugarLevel) { _sugarLevel = sugarLevel; return this; }
    public LatteBuilder SetMilk(MilkType milkType) { _milkType = milkType; return this; }

    // 統一在這組裝,也是集中放驗證邏輯的好地方
    public Latte Build()
    {
        return new Latte(_size, _iceLevel, _sugarLevel, _milkType);
    }
}

Singleton 管的維度跟前面三個都不同

Factory Method、Abstract Factory、Builder 談的都是「怎麼生」

Singleton 談的是「生出來的東西,全域該不該只存在一份」。它幾乎可以跟任何一個 Pattern 同時出現,比如 MachineDriver 這個 Singleton,內部要接一台複雜的硬體,一樣可以用 Builder 組裝它的連線設定

public sealed class MachineDriver
{
    // 1. 用 Lazy<T> 包一層,確保「第一次真的有人要點餐」時才建立這條連線,且天生執行緒安全
    private static readonly Lazy<MachineDriver> _instance = new(() => new MachineDriver());

    // 2. 唯一的全域存取點
    public static MachineDriver Instance => _instance.Value;

    // 3. 建構子上鎖,外部沒辦法自己 new MachineDriver()
    private MachineDriver()
    {
        Console.WriteLine("--> 正在連線咖啡機硬體...");
        // 這裡會開 TCP / Serial 連線,跟咖啡機握手
    }

    public void Brew(string drinkName)
    {
        Console.WriteLine($"正在萃取:{drinkName}");
    }
}

Prototype 站在 Factory/Builder 的對立面

Factory Method 跟 Builder 都是「照著配方從零組裝一次」

Prototype 是「不想每次都重新照配方走一次,直接拿現成的複製,改一點點就好」

同樣是拿鐵需求,Day 11 用 LatteBuilder 從零組,Day 13 用 Clone() 複製標準原型,兩條路線是互補

建構便宜、選項單純時用 Builder 現組;有現成的標準品、只想微調時用 Prototype 複製

public class ChaiLatte
{
    // ...前面屬性保持不變
    public List<string> Toppings { get; set; } = new List<string>();

    public ChaiLatte Clone()
    {
        // 1. 先透過 MemberwiseClone 複製基本型別
        var clone = (ChaiLatte)this.MemberwiseClone();

        // 2. 手動為參考型別(List)建立一份全新實體(深拷貝)
        clone.Toppings = new List<string>(this.Toppings);
        return clone;
    }
}

該用哪一個?先問自己這幾題

  1. 這個物件本身建構複雜、參數很多嗎? 是 → 考慮 Builder
  2. 是不是有好幾種變體的同一類產品,以後還可能再加新的? 是 → 考慮 Factory Method
  3. 是不是有好幾種產品綁在一起、不能混搭? 是 → 考慮 Abstract Factory
  4. 建構這個物件的成本很高,或大部分欄位其實都跟現成的一樣,只改一點點? 是 → 考慮 Prototype
  5. 這個資源在系統裡該不該存在超過一份? 不該 → 考慮 Singleton(但這一條跟前面四條不衝突,可以同時成立)

創建型五個 Pattern 一起看,能拿來檢查什麼

如果阿柴把「幫我重新設計柴咖啡的點餐系統,物件建立的部分要好維護」整包丟給 AI 處理

很容易看到一種:AI 一口氣把 Factory Method、Abstract Factory、Builder、Singleton、Prototype 全部套上去

飲料要用工廠生、套餐要用抽象工廠包、客製化要用建造者組、菜單設定弄成單例、常客配方再包一層原型

每個 Pattern 單獨看語法都對,湊在一起卻是將複雜度跟認知負擔直線上升

把這五題想清楚、明確告訴 AI「柴咖啡的規模、痛點在這裡」

AI 給出的創建型架構才會符合這間店現在需要的樣子,而不是五個 Pattern 各自處理、湊在一起卻互相打架的,然後 review 的人也不懂 design pattern,不知從何維護


明天開始進入結構型 Pattern,柴咖啡要跟外送平台談合作了我們,先從 Decorator 處理開始


上一篇
Day 13|Prototype(原型模式) 用複製原型,整理客製化訂單
下一篇
Day 15|Decorator(裝飾器模式) 解開扣款後續任務的組合難題
系列文
一杯咖啡的設計課:30 天 Design Pattern 的自我修煉26
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言