- 工廠方法模式:通過選取相關的實例化方法來滿足組件的調用請求,而調用組件不需要了解具體的實例化細節。
- 什麼時候可以用:當存在多個類共同實現一個協議或者共同繼承一個類的時候,可以使用「工廠方法模式」。
餅乾店
今天我們在一家非常有名的餅乾店工作,我們不僅生產各種餅乾,並且還提供包裝服務。
餅乾店的產品分成三種類型:
- Small Product – 5 片以下,包裝費 10 元。
- Big Product – 6~10 片,包裝費 20 元。
- Large Product – 11 ~15 片,包裝費 30 元。
現在店裏接到一系列訂單,餅乾數量分別為:
1 |
1, 3, 5, 9, 12 |
需要你幫忙產出對應的 Product Array, 最後 print 出每一個商品含包裝的價格。
員工收到訂單後馬上開始生產
定義盒子的類型
1 2 3 4 5 |
enum BoxType { case smallBox case bigBox case largeBox } |
定義 Product 基礎類
1 2 3 4 5 6 7 8 9 10 11 |
class Product { var boxType:BoxType var amount:Int var packagePrice:Int init(boxType:BoxType, amount:Int){ self.boxType = boxType self.amount = amount self.packagePrice = 0 } } |
定義三種 Product
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class SmallProduct:Product { init(amount:Int){ super.init(boxType: .smallBox, amount: amount) self.packagePrice = 10 } } class BigProduct:Product { init(amount:Int){ super.init(boxType: .bigBox, amount: amount) self.packagePrice = 20 } } class LargeProduct:Product { init(amount:Int){ super.init(boxType: .largeBox, amount: amount) self.packagePrice = 30 } } |
最後根據訂單的數量去實例化不同大小的產品,放在 products 中
1 2 3 4 5 6 7 8 9 |
let orders = [1,3,5,9,12]; let product1 = SmallProduct(amount: 1) let product2 = SmallProduct(amount: 3) let product3 = SmallProduct(amount: 5) let product4 = BigProduct(amount: 9) let product5 = LargeProduct(amount: 12) let products = [product1, product2, product3, product4, product5] |
分別 print 出每一個產品包含包裝的價格
1 2 3 |
for product in products { print("price: \(product.amount * 10 + product.packagePrice)") } |
這樣似乎就完成了,但如果餅乾店對於不同產品數量的規則改變時該怎麼辦呢?
比如不同包裝的餅乾數量改變了:
- SmallProduct – 0 到 15 個餅乾
- BigProduct – 16 到 20 個餅乾
- LargeProduct – 21 到 30 個餅乾
這時候原本的 code 就要從
1 2 3 4 5 6 7 |
let orders = [1,3,5,9,12]; let product1 = SmallProduct(amount: 1) let product2 = SmallProduct(amount: 3) let product3 = SmallProduct(amount: 5) let product4 = BigProduct(amount: 9) let product5 = LargeProduct(amount: 12) |
都修改成 SmallProduct
1 2 3 4 5 6 7 |
let orders = [1,3,5,9,12]; let product1 = SmallProduct(amount: 1) let product2 = SmallProduct(amount: 3) let product3 = SmallProduct(amount: 5) let product4 = SmallProduct(amount: 9) let product5 = SmallProduct(amount: 12) |
每一次規則改變都要手動去修改對應的類別,有沒有更好的作法呢?
改良版作法
我們將「選擇實例化的對象」以及具體「實例化的過程」給包裝了起來,於是調用組件僅需要告訴工廠餅乾的數量就可以取得不同類型的產品。
我們建立一個工廠 ProductFactory, 並提供一個生產邏輯
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class ProductFactory { class func generateProducts(amount:Int) -> Product?{ switch amount { case 0...5: return SmallProduct(amount: amount) case 6...10: return BigProduct(amount: amount) case 11...15: return LargeProduct(amount: amount) default: return nil } } } |
每當生產規則改變的時候,就只需要去修改 ProductFactory 就搞定了。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
let orders = [1,3,5,9,12]; var products = [Product?]() for order in orders { products.append(ProductFactory.generateProducts(amount: order)) } for product in products { if let product = product { print("price: \(product.amount * 10 + product.packagePrice)") } } |
我們常常在一個項目中有時會定義幾種 UIButton 類型、UITextField 類型,甚至UILabel 類型,也都可以通過工廠方法模式來生產所需要的組件。
其他參考
- 可以到Github上查看本文提到的工廠方法模式例子。