上一篇講到簡單工廠方法,這篇文章介紹它的延申: 工廠方法
適合場景
有二個以上、功能相近但細節稍有不同的資料結構或實作,且隨著業務增長會不斷增加實作的情況。例如本來只服務台灣的電商平台,需要擴展到海外,其寄送方式和服務商會大幅增加。
範例
一樣以電商的物流為例,如何使用工廠模式解決不斷增加的寄送方式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| class Delivery { constructor(shipAddress) { this.shipAddress = shipAddress; this.shippingRate = 0; this.freeShipmentThreshold = 0; this.traceNumber = ''; } get shippingRate() { return this.shippingRate; }
get freeShipmentThreshold() { return this.freeShipmentThreshold; }
set traceNumber() {}
get traceNumber() { return this.traceNumber; } } class ConvenienceStoreDelivery : Delivery { constructor(shipAddress) { this.shipAddress = shipAddress; this.shippingRate = 100; this.freeShipmentThreshold = 2000; this.traceNumber = ''; } set traceNumber() {} } class PostOfficeDelivery : Delivery { constructor(shipAddress) { this.shipAddress = shipAddress; this.shippingRate = 80; this.freeShipmentThreshold = 1000; this.traceNumber = ''; } set traceNumber() {} }
|
宣告各物流服務後,接下來是建立工廠類別介面和實作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class IDeliveryFactory { createDeliveryService(shipAddress) { throw new Error('Implement me!'); } } class ConvenienceStoreDeliveryFactory : IDeliveryFactory { createDeliveryService(shipAddress) { return new ConvenienceStoreDelivery(shipAddress); } } class PostOfficeDeliveryFactory : IDeliveryFactory { createDeliveryService(shipAddress) { return new PostOfficeDelivery(shipAddress); } }
|
用戶端
1 2 3
| const factory = new ConvenienceStoreDeliveryFactory(); const convenienceStoreDelivery = factory.createDeliveryService(shipAddress);
|
乍看之下多了不少程式碼,但工廠方法的優點在於新增實作不會違反開放-封閉原則,不用每次都要修改switch case,將判斷拉到用戶端。
注意事項
- 不建議一開始就使用工廠方法,也許簡單工廠方法就能應付,等到業務需求大增再改就好
- 此方法對用戶端有額外的判斷,若太多用戶端都需要使用會造成負擔,要靠其它方法解決