良好的設計模式能夠顯著提升代碼的可讀性,下降複雜度和維護成本。筆者打算經過幾篇文章通俗地講一講常見的或者實用的設計模式。編程
今天先從最簡單的一個入手:單例模式。設計模式
文中的示例代碼會使用 ES6 語法,儘可能簡化沒必要要的細節
單例模式(Singleton)屬於建立型的設計模式,它限制咱們只能建立單一對象或者某個類的單一實例。緩存
一般狀況下,使用該模式是爲了控制整個應用程序的狀態。在平常的開發中,咱們遇到的單例模式可能有:Vuex 中的 Store,Vue 的根實例,任何導出單個對象的 ES6 模塊等。模塊化
最簡單的單例其實就像下面這樣:函數
const cat = { name: 'mi', age: 4 }
瞭解 const
語法的小夥伴都知道,這隻喵是不能被從新賦值的,可是它裏面的屬性實際上是可變的。this
若是想要一個不可變的單例對象:spa
const cat = { name: 'mi', age: 4 } Object.freeze(cat);
這樣就不能新增或修改這隻喵上的任何屬性,它變成了 冰凍喵~ 設計
若是是在模塊中使用,上面的寫法並不會污染全局做用域,可是直接生成一個固定的對象缺乏了一些靈活性。code
相對而言,使用類或工廠方法來實現單例更加經常使用。假設咱們有一個叫做 Logger
的類,它具備和 Console
相同的 API。對象
類的單例寫法很是經常使用,若是咱們想要這麼使用它:
const logger = new Logger(); logger.log('msg'); // 這裏大概寫了 1000 行代碼 const logger2 = new Logger(); logger.log('new msg'); logger === logger2; // true
即儘管 new
了屢次 Logger
,它返回的都是同一個實例。
下面直接看最實用的實現方式:
class Logger { constructor () { if (!Logger._singleton) { Logger._singleton = this; } return Logger._singleton; } log (...args) { console.log(...args); } } export default Logger;
上面的方式將單例對象存儲在了構造器上,這樣的話無論 new Logger
多少次,返回的都是同一個 Logger 實例了。
這裏有一個細節須要注意,即 new
關鍵字後面的構造函數若是顯式返回一個對象,new
表達式就會返回該對象。
具體可參見 《你不知道的 JavaScript (上卷)》中的 new 綁定 相關章節。
若是不喜歡用 new 關鍵字,可使用工廠方法返回單例對象。
let logger = null class Logger { log (...args) { console.log(...args); } } function createLogger() { if (!logger) { logger = new Logger(); } return logger; } export default createLogger;
上面的代碼至關於在模塊內部緩存了 logger 實例,而後導出了一個工廠方法。這種寫法在模塊化代碼中比較常見,工廠方法也能夠接收參數用來初始化單例對象。
今天的內容比較好理解,其中的單例寫法也是筆者經常使用的方法。
下一篇咱們再具體講講工廠模式的應用~
本文首發於公衆號:碼力全開(codingonfire)
本文隨意轉載哈,註明原文連接便可,公號文章轉載聯繫我開白名單就好~