diff --git a/_posts/2022-02-13-design-pattern-4-simple-factory-pattern.markdown b/_posts/2022-02-13-design-pattern-4-simple-factory-pattern.markdown new file mode 100644 index 0000000..72249b1 --- /dev/null +++ b/_posts/2022-02-13-design-pattern-4-simple-factory-pattern.markdown @@ -0,0 +1,172 @@ +--- +layout: single +title: "Design Pattern 系列 (4) - Simple Factory Pattern" +date: 2022-02-13 23:45:00 +0800 +excerpt: "將會變動的創建物件程式碼與不會變動的程式碼分開吧,增加程式碼可讀性及維護性" +header: + overlay_image: /assets/images/vindemia-winery-wGk29doZtpQ-unsplash.jpg + teaser: /assets/images/vindemia-winery-wGk29doZtpQ-unsplash.jpg +tags: [Simple Factory Pattern] +categories: [Design Pattern] +--- + +> 您可於此 [design_pattern repo](https://github.com/nickhuang9527/design_pattern) 下載 Design Pattern 系列程式碼。 + +今天我們想做一套飲料點餐系統,很快的我們畫出 UML 並寫出了下面的程式碼 + +![design_pattern_4_simple_factory_pattern_uml_1](/blog/assets/images/design_pattern_4_simple_factory_pattern_uml_1.png) + +```swift +public protocol Beverage { + func addSuger(level: Int) + func addIce(level: Int) + func shake() + func packageUp() +} + +public extension Beverage { + func addSuger(level: Int) { + print("[\(self)] addSuger \(level)") + } + + func addIce(level: Int) { + print("[\(self)] addIce \(level)") + } + + func shake() { + print("[\(self)] shake") + } + + func packageUp() { + print("[\(self)] packageUp") + } +} + +public class BlackTea: Beverage { + +} + +public class GreenTea: Beverage { + +} + +public class BeverageShop { + public init() {} + + public func order(beverageName: String) -> Beverage? { + var beverage: Beverage? + + switch beverageName { + case "black tea": + beverage = BlackTea() + case "green tea": + beverage = GreenTea() + default: + break + } + + beverage?.addSuger(level: 5) + beverage?.addIce(level: 5) + beverage?.shake() + beverage?.packageUp() + + return beverage + } +} + +let beverageShop = BeverageShop() +let blackTea = beverageShop.order(beverageName: "black tea") +let greenTea = beverageShop.order(beverageName: "green tea") +``` + +隨著飲料店越來越多新飲品,我們也需要修改 order 方法,但這樣容易影響不會變動的程式碼,於是我們需要找出 `需要變動` 以及 `不需變動` 的程式碼,把它們分隔開來 + +需要變動的程式碼 + +```swift +switch beverageName { +case "black tea": + beverage = BlackTea() +case "green tea": + beverage = GreenTea() +// case "milk tea": + // beverage = MilkTea() +default: + break +} +``` + +不需變動的程式碼 + +```swift +beverage?.addSuger(level: 5) +beverage?.addIce(level: 5) +beverage?.shake() +beverage?.packageUp() +``` + +找出後該如何做呢,這時候需要用到 `簡單工廠模式` 來將其分離 + +## Simple Factory Pattern 簡單工廠模式 + +其實就是定義一個工廠類別來專門處理創建物件的邏輯 +那就讓我們修改一下上面的 UML 及程式碼吧 + +![design_pattern_4_simple_factory_pattern_uml_2](/blog/assets/images/design_pattern_4_simple_factory_pattern_uml_2.png) + +```swift +class BeverageFactory { + class func createBeverage(beverageName: String) -> Beverage? { + var beverage: Beverage? + + switch beverageName { + case "black tea": + beverage = BlackTea() + case "green tea": + beverage = GreenTea() + default: + break + } + + return beverage + } +} + +public class BeverageShop { + public init() {} + + public func order(beverageName: String) -> Beverage? { + let beverage: Beverage? = BeverageFactory.createBeverage(beverageName: beverageName) + + beverage?.addSuger(level: 5) + beverage?.addIce(level: 5) + beverage?.shake() + beverage?.packageUp() + + return beverage + } +} +``` + +透過簡單工廠模式,我們就將 `需要變動` 以及 `不需變動` 的程式碼成功分隔開來,當要修改菜單時,只需修改 `BeverageFactory` 即可,不會影響到其他程式碼。 + +> 簡單工廠其實不是設計模式,反而比較像是一種編成習慣 +> +> 有些開發者的確是把這個編成習慣誤認為 `工廠模式` (Factory Pattern) +> +> 不要因為簡單工廠不是一個 `真正的` 模式,就忽略了它的用法。 +> +> -- Head First Design Pattern Ch.4 P.117 + +最後來看一下 `簡單工廠模式` 的 UML 圖 +![design_pattern_4_simple_factory_pattern_uml_3](/blog/assets/images/design_pattern_4_simple_factory_pattern_uml_3.png) + +## 總結 + +簡單工廠雖然不是 23 個設計模式之中的一種,但它非常簡單,且能訓練我們將變動及不會變動的程式碼分離的習慣 +來看一下我們在簡單工廠用到了哪些 [Design Principle](https://nickhuang9527.github.io/blog/design%20pattern/design-pattern-1-design-principle/) + +- Encapsulate What Varies +- Single Responsibility Principle + +下一篇正式進入 23 個 Design Pattern 的第一個 Factory Method Pattern 工廠方法模式 diff --git a/assets/images/carlos-aranda-QMjCzOGeglA-unsplash.jpg b/assets/images/carlos-aranda-QMjCzOGeglA-unsplash.jpg new file mode 100644 index 0000000..2eb7b0b Binary files /dev/null and b/assets/images/carlos-aranda-QMjCzOGeglA-unsplash.jpg differ diff --git a/assets/images/design_pattern_4_simple_factory_pattern_uml_1.png b/assets/images/design_pattern_4_simple_factory_pattern_uml_1.png new file mode 100644 index 0000000..c80dd79 Binary files /dev/null and b/assets/images/design_pattern_4_simple_factory_pattern_uml_1.png differ diff --git a/assets/images/design_pattern_4_simple_factory_pattern_uml_2.png b/assets/images/design_pattern_4_simple_factory_pattern_uml_2.png new file mode 100644 index 0000000..b6d3545 Binary files /dev/null and b/assets/images/design_pattern_4_simple_factory_pattern_uml_2.png differ diff --git a/assets/images/design_pattern_4_simple_factory_pattern_uml_3.png b/assets/images/design_pattern_4_simple_factory_pattern_uml_3.png new file mode 100644 index 0000000..6c05cc0 Binary files /dev/null and b/assets/images/design_pattern_4_simple_factory_pattern_uml_3.png differ diff --git a/assets/images/lenny-kuhne-jHZ70nRk7Ns-unsplash.jpg b/assets/images/lenny-kuhne-jHZ70nRk7Ns-unsplash.jpg new file mode 100644 index 0000000..23d7ff9 Binary files /dev/null and b/assets/images/lenny-kuhne-jHZ70nRk7Ns-unsplash.jpg differ diff --git a/assets/images/vindemia-winery-wGk29doZtpQ-unsplash.jpg b/assets/images/vindemia-winery-wGk29doZtpQ-unsplash.jpg new file mode 100644 index 0000000..5d36dec Binary files /dev/null and b/assets/images/vindemia-winery-wGk29doZtpQ-unsplash.jpg differ