一、什么是工廠模式?
工廠模式屬于創建型設計模式,核心思想是將對象的實例化過程封裝到特定方法或類中,讓客戶端不需要直接通過new
關鍵字創建對象。
舉個例子:就像奶茶店不需要顧客自己調配飲品,而是通過"點單-制作"的流程解耦需求與實現。
// 簡單工廠示例:按鈕組件生成器
interface Button {render(): void;
}class PrimaryButton implements Button {render() {console.log("渲染藍色主按鈕");}
}class DangerButton implements Button {render() {console.log("渲染紅色警示按鈕");}
}// 工廠方法(這里用函數式實現更符合前端習慣)
function createButton(type: 'primary' | 'danger'): Button {switch(type) {case 'primary':return new PrimaryButton();case 'danger':return new DangerButton();default:throw new Error("未知按鈕類型");}
}// 客戶端調用
const submitBtn = createButton('primary');
submitBtn.render(); // 輸出:渲染藍色主按鈕
二、工廠模式的三種形態
- ??簡單工廠??:通過一個方法集中處理所有創建邏輯(適合類型較少的情況)
- ??工廠方法??:定義抽象工廠接口,由子類決定實例化哪個類(符合開閉原則)
- ??抽象工廠??:創建相關或依賴對象的家族(適合復雜產品線)
三、核心優勢
- ??解耦創建邏輯??:將易變的創建過程隔離,修改創建邏輯只需調整工廠
- ??類型系統友好??:配合接口使用能保證返回對象的一致性
- ??簡化復雜創建??:隱藏對象初始化時的復雜依賴關系(如需要多個服務注入)
// 工廠方法模式示例:跨平臺UI組件
abstract class Dialog {abstract createButton(): Button;render() {const button = this.createButton();button.render();}
}class WindowsDialog extends Dialog {createButton() {return new WindowsButton(); // 假設有具體實現}
}class WebDialog extends Dialog {createButton() {return new HtmlButton(); // 瀏覽器環境專用按鈕}
}// 運行時根據環境選擇工廠
const currentDialog = isMobile ? new WebDialog() : new WindowsDialog();
currentDialog.render();
四、典型使用場景
- ??組件庫開發??:根據不同主題生成樣式化的組件
- ??跨平臺適配??:為不同運行環境生成對應實現
- ??對象池管理??:統一管理相似對象的創建和回收
- ??配置驅動UI??:根據JSON配置動態生成界面元素
五、必須注意的坑
- ??過度設計警告??:如果類型不超過3個,直接
switch-case
可能更簡單 - ??類型擴散問題??:每新增一個產品就需要對應工廠,可能造成類爆炸
- ??調試復雜度??:代碼執行鏈路變長,需要跳轉多個工廠類
- ??實例狀態管理??:工廠創建的對象如果包含狀態需要特別注意生命周期
// 合理使用示例:動態表單控件工廠
class ControlFactory {private registry = new Map<string, ControlConstructor>();register(type: string, constructor: ControlConstructor) {this.registry.set(type, constructor);}create(type: string, config: ControlConfig) {const Constructor = this.registry.get(type);if (!Constructor) throw new Error(`未注冊的控件類型: ${type}`);return new Constructor(config);}
}// 注冊自定義控件
factory.register('color-picker', ColorPickerControl);
factory.register('rating', StarRatingControl);// 根據后端配置動態生成
const configFromAPI = [{ type: 'color-picker', label: '主題色' }];
configFromAPI.forEach(c => {const control = factory.create(c.type, c);formContainer.appendChild(control.render());
});
六、性能優化策略
- ??對象緩存??:對頻繁創建且無狀態的對象進行復用
- ??惰性加載??:推遲創建高消耗對象直到真正需要時
- ??Tree-shaking優化??:將不同實現分離到獨立模塊
// 帶緩存的對象池工廠
class ModelPool {private pool = new Map<string, THREE.Object3D[]>();get(modelName: string) {if (!this.pool.has(modelName)) {this.pool.set(modelName, []);}const available = this.pool.get(modelName)!.filter(m => !m.visible);if (available.length > 0) {return available[0];}const newModel = this.loadModel(modelName);this.pool.get(modelName)!.push(newModel);return newModel;}private loadModel(name: string) {// 實際加載3D模型的實現}
}
七、面試考點解析
當候選人回答該問題時,需重點考察:
- 是否能區分三種工廠模式的應用場景
- 能否識別過度使用工廠模式帶來的問題
- 是否具備實際項目中的優化經驗
- 對TypeScript類型系統的運用能力
??陷阱問題示例??:
"假設需要支持插件系統,允許第三方注冊新控件類型,工廠模式該如何改進實現?"
期望答案應涉及:
- 注冊機制的設計
- 類型安全的實現
- 生命周期管理
- 防沖突處理
八、現代前端框架中的實踐
- ??React Context + 工廠模式??:通過Context傳遞主題工廠
const ThemeContext = createContext<ButtonFactory>(defaultFactory);function App() {return (<ThemeContext.Provider value={materialFactory}><FormPage /> // 內部組件使用統一工廠創建元素</ThemeContext.Provider>);
}
- ??Vue組合式API工廠??:創建可復用的組件邏輯
export function useFormControl(factory: ControlFactory) {const controls = ref([]);function addControl(config) {controls.value.push(factory.create(config));}return { controls, addControl };
}
九、決策流程圖
是否需要使用工廠模式?問以下問題:
- 是否需要支持多種實現變體??→ 考慮工廠
- 對象創建是否包含復雜初始化??→ 需要封裝
- 是否需要集中管理對象生命周期??→ 適合工廠
- 未來是否可能有新增類型??→ 工廠方法更優
十、推薦學習路徑
- 從簡單工廠開始實踐,逐步理解抽象的必要性
- 研究主流UI庫的組件創建實現(如Material-UI的withStyles)
- 結合DI容器理解工廠的進階應用
- 學習相關模式:建造者模式、策略模式、模板方法模式
工廠模式就像代碼界的樂高積木生產線,關鍵在于在靈活性和復雜度之間找到平衡點。
掌握其精髓后,面對多變的需求就能快速搭建出可維護的架構。