這篇文章會以 JavaScript 的 Creational Pattern 開始介紹,建立型模式是處理物件建立的設計模式,實作上會根據實際情況使用合適的方式建立物件,幾種方式如下
Class Design Pattern Constructor Pattern Singleton Pattern Factory Pattern Abstract Factory Pattern Design Patterns 依照目的分成三群:
Class Design Pattern 這個其實算常見,基於 prototype 的基礎在 ECMAScript 6 被實作,讓我們可以用模擬物件導向方式去建立物件。
Class 是一個定義檔,去定義出 “未來產生的” 物件應該要長什麼樣子以及該怎麼被使用。
在使用 Class 時必須使用 new 這個關鍵字用 Class 去產生出新的 Instance 作為物件來被使用。
1 2 3 4 5 6 7 8 9 10 11 class Motorcycle { constructor (license, volume ) { this .license = license; this .volume = volume; } } const motor125 = new Motorcycle ("white" , 125 );const motor50 = new Motorcycle ("white" , 50 );console .log (motor125);console .log (motor50);
執行程式碼的結果
Motorcycle {license: ‘white’, volume: 125} Motorcycle {license: ‘white’, volume: 50}
Constructor Pattern 以 Class Design Pattern 延伸出的就是 Constructor Pattern,讓我們可以沿用父類別 constructor 已經定義過的變數和沿用該變數該有的行為。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Motorcycle { constructor (license, volume ) { this .license = license; this .volume = volume; } } class SymMotor extends Motorcycle { constructor (license, volume ) { super (license, volume); this .brand = "sym" ; } } const symMotorGreenLicense = new SymMotor ("green" , 50 );const symMotorWhiteLicense = new SymMotor ("white" , 125 );console .log (symMotorGreenLicense);console .log (symMotorWhiteLicense);
執行程式碼的結果
SymMotor {license: ‘green’, volume: 50, brand: ‘sym’} SymMotor {license: ‘white’, volume: 125, brand: ‘sym’}
React 初期的 class component 就是運用這個來實作出元件,super 會參照父類別的 constructor,並且要在呼叫過後才可以叫用 this,所以我們可以去使用已經在父類別裡面已經被定義過的 props,以 Motorcycle 當例子就是 license 和 volume 都已經被定義過且被使用。
如果在寫 Super 前就先使用 this 去定義 function 若 function 有使用到 props 的內容就會造成未定義的問題,所以在 constructor 中使用 this,JavaScript 強制必須先呼叫 super。
那為什麼要寫一個 super(props);
當參數,原因就在 React 原始碼 裡。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function Component (props, context, updater ) { this .props = props; this .context = context; this .refs = emptyObject; this .updater = updater || ReactNoopUpdateQueue ; } Component .prototype .isReactComponent = {};
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Input extends React.Component { constructor ( ) { this .handleInputInit (); super (props); this .state = { input : "" }; this .handleInput = this .handleInput .bind (this ); } handleInputInit ( ) { } handleInput (e ) { this .setState ({ input : e.target .value }); } render ( ) { <input onChange ={handleInput} value ={this.state.input} /> ; } }
Singleton Pattern 單體模式算是小編接觸的第一個設計模式,目標很清楚就是要持久化一個物件,當未來每次要產生物件時其實都是使用同一個 Instance 的物件內容。
不過較常使用在後端,讓用於資料庫連線的物件只會有一個。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 let instance = null ;class Motorcycle { constructor (license, volume ) { if (instance) return instance; if (!instance) { this .license = license; this .volume = volume; instance = this ; } } } const motor125 = new Motorcycle ("white" , 125 );const motor50 = new Motorcycle ("white" , 50 );console .log (motor125);console .log (motor50);
執行程式的結果可以發現都是相同物件的內容,新的 new 其實並沒有產生新的物件出來。
Motorcycle {license: ‘white’, volume: 125} Motorcycle {license: ‘white’, volume: 125}
Factory Pattern 工廠模式顧名思義就是去定義出類似工廠概念的 class,工廠是按照規格把東西做出來。
所以 Factory Pattern 就會是專注定義規格,並且提供 function 讓使用者可以將物件製造出來。
底下的例子我們就來定義機車的規格
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 class Motorcycle { constructor (license, volume ) { this .license = license; this .volume = volume; } } class MotorFactory { createMotor ({ volume } ) { if (volume <= 50 ) { return new Motorcycle ("green" , volume); } if (volume < 150 ) { return new Motorcycle ("white" , volume); } } } const motorFactory = new MotorFactory ();const motorGreenLicense = motorFactory.createMotor ({ volume : 50 });const motorWhiteLicense = motorFactory.createMotor ({ volume : 125 });console .log (motorGreenLicense);console .log (motorWhiteLicense);
執行程式碼的結果
Motorcycle {license: ‘green’, volume: 50} Motorcycle {license: ‘white’, volume: 125}
如果要寫出一個 react 版本的
1 2 3 4 5 6 7 8 9 function factory (params ) { const condition = "some condition" ; if (condition) { return <ProductA params ={params} /> ; } else { return <ProductB params ={params} /> ; } }
Abstract Factory Pattern Abstract Factory 只是 Factory Pattern 延伸的概念,以現實狀況來說就是一個代工廠。
小編現在剛好就在代工廠上班,代工廠做的事情是在某個規格的基礎上,依照各品牌去做相關的客製化做代工,舉例來說常見的鞋子、筆電等等,其實都是由代工廠為各個品牌進行製造的。
以廣達當作 Abstract Factory 來看,實際的代工出來的就會有 HP、Toshiba、Sony、Lenovo 等等品牌筆電。
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 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 class Motorcycle { constructor (license, volume ) { this .license = license; this .volume = volume; } } class SymMotor extends Motorcycle { constructor (license, volume ) { super (license, volume); this .brand = "sym" ; } } class KymcoMotor extends Motorcycle { constructor (license, volume ) { super (license, volume); this .brand = "Kymco" ; } } class SymMotorFactory { createMotor (volume ) { if (volume <= 50 ) { return new SymMotor ("green" , volume); } if (volume < 150 ) { return new SymMotor ("white" , volume); } } } class KymcoMotorFactory { createMotor (volume ) { if (volume <= 50 ) { return new KymcoMotor ("green" , volume); } if (volume < 150 ) { return new KymcoMotor ("white" , volume); } } } const symMotorFactory = new SymMotorFactory ();const kymcoMotorFactory = new KymcoMotorFactory ();const motorFactory = ({ brand, volume } ) => { if (brand === "sym" ) { return symMotorFactory.createMotor (volume); } if (brand === "kymco" ) { return kymcoMotorFactory.createMotor (volume); } }; const symMotorGreenLicense = motorFactory ({ brand : "sym" , volume : 50 });const kymcoMotorGreenLicense = motorFactory ({ brand : "kymco" , volume : 50 });const symMotorWhiteLicense = motorFactory ({ brand : "sym" , volume : 125 });console .log (symMotorGreenLicense);console .log (symMotorWhiteLicense);console .log (kymcoMotorGreenLicense);
程式執行結果
SymMotor {license: ‘green’, volume: 50, brand: ‘sym’} SymMotor {license: ‘white’, volume: 125, brand: ‘sym’} KymcoMotor {license: ‘green’, volume: 50, brand: ‘Kymco’}
喜歡這篇文章,請幫忙拍拍手喔 🤣