
你看過這種 constructor 嗎?
new Report('Monthly Sales', true, false, 'bar', null, 'auto', 'Generated');第三個參數是什麼?第五個 null 代表什麼意思?沒有人知道。連寫的人三天後也不知道了。
先講結論
Builder Pattern 把物件的建立過程拆成一連串有意義的步驟。每一步都有明確的 method 名稱,最後呼叫 build() 產出成品。程式碼自帶文件,一看就懂。
classDiagram class ReportDirector { -builder : ReportBuilder +buildMonthlyReport() Report } class ReportBuilder { -report : Report +setTitle(title) ReportBuilder +addChart(chart) ReportBuilder +addTable(table) ReportBuilder +setNotes(notes) ReportBuilder +build() Report } class Report { -title : String -charts : Array -tables : Array -notes : String } ReportDirector --> ReportBuilder : 指揮建立流程 ReportBuilder --> Report : 產出
用 Builder 重寫

class Report {
constructor() {
this.title = '';
this.charts = [];
this.tables = [];
this.notes = '';
}
}
class ReportBuilder {
constructor() { this.report = new Report(); }
setTitle(title) {
this.report.title = title;
return this; // return this 才能 chain
}
addChart(chart) {
this.report.charts.push(chart);
return this;
}
addTable(table) {
this.report.tables.push(table);
return this;
}
setNotes(notes) {
this.report.notes = notes;
return this;
}
build() { return this.report; }
}
// 看這段 code,你不用看文件就知道在建什麼
const report = new ReportBuilder()
.setTitle('Monthly Sales Report')
.addChart({ type: 'bar', data: [100, 200, 150] })
.addTable({ headers: ['Product', 'Sales'], rows: [] })
.setNotes('Generated automatically')
.build();每個步驟都有名字,順序隨你排,不需要的步驟可以跳過。比起那串看不懂的 constructor 參數,這段 code 根本是自帶說明書。
Director:預設組合
如果某種 Report 組合很常用,可以用 Director 封裝起來:
class ReportDirector {
constructor(builder) { this.builder = builder; }
buildMonthlyReport() {
return this.builder
.setTitle('Monthly Sales Report')
.addChart({ type: 'bar', data: [100, 200, 150] })
.setNotes('Auto-generated')
.build();
}
}但說實話,在 JavaScript 裡 Director 不一定需要——直接寫一個 factory function 也能達到同樣效果。Builder Pattern 的核心價值在 Builder 本身,不在 Director。
什麼時候用 Builder?
- Constructor 參數超過 4 個
- 有些參數是可選的
- 物件的建立有明確的步驟
如果你的物件就三個欄位,直接用 constructor 或 object literal 就好。不用每個東西都 Builder 一下。
Builder Pattern 就像訂製漢堡——你一步步選麵包、選肉排、選醬料,最後拿到你要的。比起「請給我第 37 號套餐」,你至少知道自己在吃什麼。