---
# System prepended metadata

title: PK - 創建模式
tags: [Java 設計模式]

---

---
title: 'PK - 創建模式'
disqus: kyleAlien
---

PK - 創建模式
===

## Overview of Content

創建模式包括工廠、抽象工廠、Builder、單例、原型模式，這些模式可以提供物件的創建（甚至管理）；其中工廠、抽象工廠、Builder 的概念較容易混淆

:::success
* 如果喜歡讀更好看一點的網頁版本，可以到我新做的網站 [**DevTech Ascendancy Hub**](https://devtechascendancy.com/)
    
    本篇文章對應的是 [**創建模式 – 3 個 PK | Factory vs Builder vs Abstract Factory | 最佳實踐**](https://devtechascendancy.com/pk-design-patterns-factory-builder-best/)
:::

[TOC]

## Factory、Builder 模式

假設兩個模式都會創建同樣的物件，那他們的差異在於

* Factory 模式：**關注於整體創建物件的方法**

* Builder 模式：**關注物件建構的過程**

### Factory 之整體

* 再次強調，站在使用者角度來說，他們 **使用 Factory 代表了，他們不關注於產品生產的細節，而關注於產品的整體**

* 以下實現一個簡單（靜態）工廠

    > ![](https://hackmd.io/_uploads/SJB64RDE3.png)

    1. **IProducr 抽象產品**：定義各個產品的共通點，好讓工廠類可以使用；工廠類則關注這個界面（契約）
    
        ```kotlin=
        interface IChair {

            fun getChairPrice() : Int

        }
        ```
    
    2. **ConcreteProduct 類**：具體產品，工廠並不關注各個產品的細節

        ```kotlin=

        class PlasticChair : IChair {

            override fun getChairPrice(): Int {
                return 300
            }

        }

        class WoodenChair : IChair {

            override fun getChairPrice(): Int {
                return 1000
            }

        }
        ```

    3. **Factory 類**：對外面對使用者的工廠類，其內部可以包裝不同細節，對外使用者則不關心這些細節，只要創建出相同產品即可；這裡我們簡單創建個類而已

        ```kotlin=
        class ChairFactory private constructor() {

            enum class ChairType {
                PLASTIC,
                WOODEN,
            }

            companion object {
                fun getChair(type: ChairType) : IChair {
                    return when(type) {
                        ChairType.PLASTIC -> PlasticChair()
                        ChairType.WOODEN -> WoodenChair()
                    }
                }
            }

        }
        ```


### Builder 之細節

* **Builder 相對來說，更關注於細節**，透過不同方式的組成（甚至可能包括組成順序）都有可能創建不同特性的產品

* 這裡我們讓 Builder 與 Factory 產品類創建相同產品

    > ![](https://hackmd.io/_uploads/Hy1tS0wN3.png)

    1. **Produce 類**：這裡的產品我們取用最簡單的實體類來看，這個產品是一個不變的產品

        ```kotlin=
        data class Chair(val price: Int, val material: ChairType) {
            enum class ChairType {
                PLASTIC,
                WOODEN,
            }
        }
        ```
        
    2. **Builder 抽象類**：Builder 是對於產品類的描述與包裝，在這個案例中 **它不會改變最終的產品實體，但是它可以對產品有不同的描述**

        ```kotlin=
        abstract class BuilderChair {

            // 對於產品的描述
            var price = 500

            var material: Chair.ChairType = Chair.ChairType.PLASTIC

            abstract fun build() : Chair

        }
        ```
        
    3. **ConcreteBuilder 類**：透過抽象 Builder 來對於產品的描述，接著 **實體類就可以依照不同特性去創建產品**

        ```kotlin=
        class PlasticChair2 : BuilderChair() {
            override fun build(): Chair {
                price = 300
                material = Chair.ChairType.PLASTIC
                return Chair(price, material)
            }

        }

        class WoodenChair2 :  BuilderChair() {

            override fun build(): Chair {
                price = 1000
                material = Chair.ChairType.WOODEN
                return Chair(price, material)
            }

        }
        ```

    4. **Director 類**：對外使用者接觸的類，**它跟 Factory 比較起來提供了更多個方法（契約），這些都代表了個別不同的產品**！

        ```kotlin=
        class Director {

            fun getWoodenChair() : BuilderChair {
                return WoodenChair2()
            }


            fun getPlasticChair() : BuilderChair {
                return PlasticChair2()
            }

        }
        ```


### Factory vs. Builder 最佳實踐

* 兩者都是用來創建物件，但我們可以關注以下兩點，就可以發現明顯的不同

    1. **意圖不同**
    
        * **Factory 關注產品的整體**，不關心產品如何產生（順序、組裝難度、使用部件... 等等都不關心），它是一個比較粗線條的創建
        
        * 相對於 Factory，**Builder 模式更加關注於產品的細節**，使用者會專注產品的組裝、選件、順序... 等等；透過細節一步一步的描繪出最終的產品

    2. **複雜度不同**

        * 既然 Factory 關注於整體，那使用者只須關注於 Factory 的契約（interface）即可，不必關注更多，相對來講 **Factory 的內聚程度高，使用起來簡單不複雜**
            
            > 單一性，缺點顯而易見，不易調整

        * 透過 Builder 創建出來的對象，都擁有一定程度上的獨特性，使用者必須關注較多的細節（或是說更多個契約），才能製造出他們想要的產品

            > 缺點跟 Factory 相反，內聚程度稍低，但可調性高


            :::success
            * 要取用哪個呢？

                **這要取決於系統（需求）設計時的意圖**，依照需求去判定、推斷要使用哪種模式
            :::

## Abstract Factory vs. Builder


* **Abstract Factory 模式**：對於使用者來說，抽象工廠隱藏細節，關注工廠產生的 Product；對於抽象工廠內部來說，透過不同的 Factory 會使用不同的 Product
    
    > 更關注產品的整體如何組合 Factory 需要的功能

    **重點在於：抽象工廠有 ++一系列生產 Product 的方法++**，透過不同維度的產品組合去支援工廠

* **Builder 模式**：建造者同上所述，它關注於產品生產的細節（順序、參數... 等等）來建構出客製化的產品

### Abstract Factory 之一系列抽象產品

* `Abstract Factory` 的重點在於，該工廠產生一系列有相關該界面的抽象產品（返回一個抽象界面給使用者操作）；以下是抽象工廠案例

    > ![](https://hackmd.io/_uploads/B1P7F3oV3.png)

    1. **Abstract Factory 界面**：該類聚集一系列的抽象，是抽象工廠的核心抽象（抽象匯聚的邊界由業務需求而定），**返回的產品也皆是抽象產品**

        ```kotlin=
        interface IHomeAppliancesFactory {
            fun getAirPurifier() : IAirPurifier

            fun getTatungAirPurifier() : IDehumidifier
        }
        ```
    
    2. **Abstract Product 界面**：這些產品界面是對於外部使用產品者的契約界面，不會提供細節

        ```kotlin=
        interface IAirPurifier {
            fun rotatable() : Boolean
        }

        // ----------------------------------------------------
        
        interface IDehumidifier {
            fun silentMode() : Int
        }
        ```
    
    3. **Concrete Product 類**：實做產品，藉由它可以實現每個產品的特色細節，但使用者不必知道，它僅需要完成對於抽象界面的契約即可

        ```kotlin=
        class LGAirPurifier : IAirPurifier {
            override fun rotatable(): Boolean {
                return true
            }
        }

        class TatungAirPurifier : IAirPurifier {
            override fun rotatable(): Boolean {
                return false
            }
        }

        // ----------------------------------------------------

        class LGDehumidifier : IDehumidifier {
            override fun silentMode(): Int {
                return 5
            }
        }

        class TatungDehumidifier : IDehumidifier {
            override fun silentMode(): Int {
                return 3
            }
        }
        ```
        
    4. **Concrete Factory 類**：該類會使用實際的產品，所以它需要知道實際產品的特色（但它仍是返回一個抽象，所以歸類唯一賴抽象）

        ```kotlin=
        class LGHomeAppliancesFactory : IHomeAppliancesFactory {
            override fun getAirPurifier(): IAirPurifier {
                return LGAirPurifier()
            }

            override fun getPhilipsAirPurifier(): IDehumidifier {
                return LGDehumidifier()
            }

        }

        // ----------------------------------------------------

        class TatungHomeAppliancesFactory : IHomeAppliancesFactory {
            override fun getAirPurifier(): IAirPurifier {
                return TatungAirPurifier()
            }

            override fun getTatungAirPurifier(): IDehumidifier {
                return TatungDehumidifier()
            }

        }
        ```
        
        :::success
        * 抽象工廠對外隱藏了實做的細節（如同工廠模式），使用只須關注每個工廠界面方法的特色（對外的契約承諾）即可，並且 **製造出來的產品注重整體性、++不可修改產品++**
        :::
        

### Builder 之自由度

* 相較起來 `Builder` 也可以作到相同的事情，不過 **它可以自由在 `Builder` 設計之內（`Director` 類），依照藍圖輕鬆調整細節（產品在最終完成前可修改）**

    > ![](https://hackmd.io/_uploads/ry6Icnj4n.png)


    1. **Builder 抽象類**：定義了產品藍圖（產品特性、最終生產類），但不定義細節

        > 這裡的 **Builder 抽象類，相對於 Abstract Factory 的抽象類**

        ```kotlin=
        abstract class HomeAppliancesBuilder {

            // 產品特性
            var rotatable = false
            var silentMode = 0

            // 最終生產類
            abstract fun createAirPurifier() : IAirPurifier

            abstract fun createDehumidifier() : IDehumidifier
        }
        ```
        
    2. **ConcreteBuilder 類**：產品的細節，負責決定最終製造出來的產品類 (這裡使用簡單的匿名類)；可以在這裡定義一些產品預設參數

        ```kotlin=
        class LGAppliancesBuilder : HomeAppliancesBuilder() {
            init {
                rotatable = true
                silentMode = 3
            }

            override fun createAirPurifier(): IAirPurifier {
                return object : IAirPurifier {
                    override fun rotatable(): Boolean {
                        return rotatable
                    }
                }
            }

            override fun createDehumidifier(): IDehumidifier {
                return object : IDehumidifier {
                    override fun silentMode(): Int {
                        return silentMode
                    }
                }
            }
        }

        class TatungAppliancesBuilder : HomeAppliancesBuilder() {
            init {
                rotatable = false
                silentMode = 5
            }

            override fun createAirPurifier(): IAirPurifier {
                return object : IAirPurifier {
                    override fun rotatable(): Boolean {
                        return rotatable
                    }
                }
            }

            override fun createDehumidifier(): IDehumidifier {
                return object : IDehumidifier {
                    override fun silentMode(): Int {
                        return silentMode
                    }
                }
            }
        }
        ```
    
    3. **Direct 類**：它是面對使用者的類，由它來決定產品的變化

        :::success
        * 從這個類中可以發現，它比起 Abstract Factory 可以更自由的調整產品的細節，決定生產更多的產品（輕鬆變化）
        :::
        ```kotlin=
        class BrandDirector {

            private val lg = LGAppliancesBuilder()
            private val tatung = TatungAppliancesBuilder()

            fun flagshipLGAirPurifier() : IAirPurifier {
                return lg.createAirPurifier()
            }

            fun basicLGAirPurifier() : IAirPurifier {
                return lg.apply {
                    rotatable = false
                }.createAirPurifier()
            }

            fun flagshipLGDehumidifier() : IDehumidifier {
                return lg.createDehumidifier()
            }

            fun basicLGDehumidifier() : IDehumidifier {
                return lg.apply {
                    silentMode = 3
                }.createDehumidifier()
            }

            fun flagshipTatungAirPurifier() : IAirPurifier {
                return tatung.createAirPurifier()
            }

            fun basicTatungAirPurifier() : IAirPurifier {
                return tatung.apply {
                    rotatable = false
                }.createAirPurifier()
            }

            fun flagshipTatungDehumidifier() : IDehumidifier {
                return tatung.createDehumidifier()
            }

            fun basicDatungDehumidifier() : IDehumidifier {
                return tatung.apply {
                    silentMode = 3
                }.createDehumidifier()
            }

        }
        ```

### Abstract Factory vs. Builder 最佳實踐


* 兩者都是用來創建多個一系列相關物件，不過他們有幾點不同

    1. **對於產品的看法不同**
        
        * **Abstract Factory 知道產品特色，但是不關心產品細節，也很少去操作產品細節**
            
            > 是用更高層次的角度來觀看產品
        
        * **Builder 知道品哪有哪些細節（並且在需要時也關注），也可以操作產品細節**

            > 使用較細節角度，去關注產品

    2. **對於產品的拓展**

        * **Abstract Factory 對於產品關住在整體，修改較費力，必須一系列產品接修改**，但它十分適合用在一個固定幾類不常變動的產品
        
        * **Builder 與之想反，產品細節的操控可以讓它快速生產不同特色的產品**，但缺點在於對於細節的操控，有點不符合開閉原則


## 更多的物件導向設計

物件導向的設計基礎如下，如果是初學者或是不熟悉的各位，建議可以從這些基礎開始認識，打好基底才能走個更穩（在學習的時候也需要不斷回頭看）！

:::info
* [**設計建模 2 大概念- UML 分類、使用**](https://devtechascendancy.com/introduction-to-uml-and-diagrams/)

* [**物件導向設計原則 – 6 大原則(一)**](https://devtechascendancy.com/object-oriented-design-principles_1/)

* [**物件導向設計原則 – 6 大原則(二)**](https://devtechascendancy.com/object-oriented-design-principles_2/)
:::


### 創建模式 - Creation Patterns

* [**創建模式 PK**](https://devtechascendancy.com/pk-design-patterns-factory-builder-best/)

* **創建模式 - `Creation Patterns`**：
    
    創建模式用於「**物件的創建**」，它關注於如何更靈活、更有效地創建對象。這些模式可以隱藏創建對象的細節，並提供創建對象的機制，例如單例模式、工廠模式… 等等，詳細解說請點擊以下連結

    :::success
    
    * [**Singleton 單例模式 | 解說實現 | Android Framework Context Service**](https://devtechascendancy.com/object-oriented_design_singleton/)

    * [**Abstract Factory 設計模式 | 實現解說 | Android MediaPlayer**](https://devtechascendancy.com/object-oriented_design_abstract-factory/)

    * [**Factory 工廠方法模式 | 解說實現 | Java 集合設計**](https://devtechascendancy.com/object-oriented_design_factory_framework/)

    * [**Builder 建構者模式 | 實現與解說 | Android Framwrok Dialog 視窗**](https://devtechascendancy.com/object-oriented_design_builder_dialog/)
    
    * [**Clone 原型模式 | 解說實現 | Android Framework Intent**](https://devtechascendancy.com/object-oriented_design_clone_framework/)

    * [**Object Pool 設計模式 | 實現與解說 | 利用 JVM**](https://devtechascendancy.com/object-oriented_design_object-pool/)

    * [**Flyweight 享元模式 | 實現與解說 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_flyweight/)
    :::


### 行為模式 - Behavioral Patterns

* [**行為模式 PK**](https://devtechascendancy.com/pk-design-patterns-cmd-strat-state-obs-chain/)

* **行為模式 - `Behavioral Patterns`**：
    
    行為模式關注物件之間的「**通信**」和「**職責分配**」。它們描述了一系列對象如何協作，以完成特定任務。這些模式專注於改進物件之間的通信，從而提高系統的靈活性。例如，策略模式、觀察者模式… 等等，詳細解說請點擊以下連結

    :::warning
    * [**Stragety 策略模式 | 解說實現 | Android Framework 動畫**](https://devtechascendancy.com/object-oriented_design_stragety_framework/)

    * [**Interpreter 解譯器模式 | 解說實現 | Android Framework PackageManagerService**](https://devtechascendancy.com/object-oriented_design_interpreter_framework/)

    * [**Chain 責任鏈模式 | 解說實現 | Android Framework View 事件傳遞**](https://devtechascendancy.com/object-oriented_design_chain_framework/)

    * [**State 狀態模式 | 實現解說 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_state/)

    * [**Specification 規格模式 | 解說實現 | Query 語句實做**](https://devtechascendancy.com/object-oriented_design_specification-query/)

    * [**Command 命令、Servant 雇工模式 | 實現與解說 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_command_servant/)

    * [**Memo 備忘錄模式 | 實現與解說 | Android Framwrok Activity 保存**](https://devtechascendancy.com/object-oriented_design_memo_framework/)

    * [**Visitor 設計模式 | 實現與解說 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_visitor_dispatch/)

    * [**Template 設計模式 | 實現與解說 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_template/)

    * [**Mediator 模式設計 | 實現與解說 | 物件導向設計**](https://devtechascendancy.com/object-oriented_programming_mediator/)

    * [**Composite 組合模式 | 實現與解說 | 物件導向設計**](https://devtechascendancy.com/object-oriented_programming_composite/)
    :::


### 結構模式 - Structural Patterns

* [**結構模式 PK**](https://devtechascendancy.com/pk-design-patterns-proxy-decorate-adapter/)

* **結構模式 - `Structural Patterns`**：
    
    結構模式專注於「物件之間的組成」，以形成更大的結構。這些模式可以幫助你確保當系統進行擴展或修改時，不會破壞其整體結構。例如，外觀模式、代理模式… 等等，詳細解說請點擊以下連結

    :::danger
    * [**Bridge 橋接模式 | 解說實現 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_bridge/)

    * [**Decorate 裝飾模式 | 解說實現 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_decorate/)

    * [**Proxy 代理模式 | 解說實現 | 分析動態代理**](https://devtechascendancy.com/object-oriented_design_proxy_dynamic-proxy/)

    * [**Iterator 迭代設計 | 解說實現 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_iterator/)

    * [**Facade 外觀、門面模式 | 解說實現 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_facade/)

    * [**Adapter 設計模式 | 解說實現 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_adapter/)
    :::


## Appendix & FAQ

:::info
:::

###### tags: `Java 設計模式`
