1. 程式人生 > 實用技巧 >Js設計模式之:單例模式

Js設計模式之:單例模式

良好的設計模式可以顯著提高程式碼的可讀性,降低複雜度和維護成本。筆者打算通過幾篇文章通俗地講一講常見的或者實用的設計模式。

今天先從最簡單的一個入手:單例模式。

文中的示例程式碼會使用 ES6語法,儘量簡化不必要的細節

概念

單例模式(Singleton)屬於建立型的設計模式,它限制我們只能建立單一物件或者某個類的單一例項。

通常情況下,使用該模式是為了控制整個應用程式的狀態。在日常的開發中,我們遇到的單例模式可能有:vuex 中的 Storevue的根例項任何匯出單個物件的 ES6 模組等。

字面量寫法

最簡單的單例其實就像下面這樣:

const cat = {
    name: 'mi',
    age: 4
}

瞭解const語法的小夥伴都知道,這隻喵是不能被重新賦值的,但是它裡面的屬性其實是可變的。

如果想要一個不可變的單例物件:

const cat = {
    name: 'mi',
    age: 4
}

Object.freeze(cat);

這樣就不能新增或修改這隻喵上的任何屬性,它變成了冰凍喵~

如果是在模組中使用,上面的寫法並不會汙染全域性作用域,但是直接生成一個固定的物件缺少了一些靈活性。

常用寫法

相對而言,使用類或工廠方法來實現單例更加常用。假設我們有一個叫作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 繫結相關章節。

電腦刺繡繡花廠 http://www.szhdn.com 廣州品牌設計公司https://www.houdianzi.com

工廠單例

如果不喜歡用 new 關鍵字,可以使用工廠方法返回單例物件。

let logger = null

class Logger {
    log (...args) {
        console.log(...args);
    }
}

function createLogger() {
    if (!logger) {
        logger = new Logger();
    }
    return logger;
}

export default createLogger;

上面的程式碼相當於在模組內部快取了 logger 例項,然後匯出了一個工廠方法。這種寫法在模組化程式碼中比較常見,工廠方法也可以接收引數用來初始化單例物件。

今天的內容比較好理解,其中的單例寫法也是筆者常用的方法。