--- 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 代表了,他們不關注於產品生產的細節,而關注於產品的整體** * 以下實現一個簡單(靜態)工廠 >  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 產品類創建相同產品 >  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` 的重點在於,該工廠產生一系列有相關該界面的抽象產品(返回一個抽象界面給使用者操作);以下是抽象工廠案例 >  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` 類),依照藍圖輕鬆調整細節(產品在最終完成前可修改)** >  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 設計模式`
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up