淺析 JS 設計模式之:工廠模式

前言

上次咱們介紹了單例模式,沒看過的小夥伴能夠看這個連接:編程

淺析 JS 設計模式之:單例模式

今天來講一說一種常見的設計模式:工廠模式。segmentfault

工廠模式是一種建立對象的 建立型模式,遵循 DRY(Don't Repeat Yourself)原則。在該模式下,代碼將會根據具體的輸入或其餘既定規則,自行決定建立哪一種類型的對象。簡單點兒說就是,動態返回須要的實例對象設計模式

回顧上次的例子

讓咱們繼續使用單例模式中的例子,一個日誌工具 Logger :api

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

上面是最核心的 api,每次使用都須要使用 new Logger() 來建立一個 logger 對象,而後使用方法就和 console 同樣啦~electron

多種 Logger

假如咱們如今的代碼要支持 electron 環境,即日誌既能夠是 console 日誌,也能夠是 file 日誌,那麼咱們就須要有兩種類型的 logger:工具

ConsoleLogger

// logger/console.js
class ConsoleLogger {
    log (...args) {
        console.log(...args)
    }
}
export default ConsoleLogger

FileLogger

// logger/file.js
class FileLogger {
    log (...args) {
        dumpLog(...args)
    }
}
export default FileLogger

這裏先不用管 dumpLog 的具體實現,只用知道它就是將日誌寫在文件中的便可~spa

使用工廠

咱們已經有了兩種類型的 logger,可是這兩種 logger 的 api 實際上都是同樣的,在項目中直接導入固然也可使用,只不過每次都要導入對應類型的模塊,而後再使用,像下面這樣:設計

使用 console logger日誌

import ConsoleLogger from './logger/console'
const logger = new ConsoleLogger()

使用 file loggercode

import FileLogger from './logger/file'
const logger = new FileLogger()

是否是很繁瑣?若是還有其餘 logger 類型,如遠程日誌,就會出現更多種使用方式了。爲了把 logger 模塊的使用方式統一,這時候就會用到工廠模式啦~

讓咱們新建一個 index.js

// logger/index.js
import ConsoleLogger from './console.js'
import FileLogger from './file.js'

function createLogger(type = 'console') {
    if (type === 'console') {
        return new ConsoleLogger()
    } else if (type === 'file') {
        return new FileLogger()
    }
    throw new Error(`Logger type not found: ${type}`)
}

export default createLogger

好了,這下咱們的使用方式就會變成這樣:

import createLogger from './logger'
// console logger
const logger1 = createLogger('console')
// file logger
const logger2 = createLogger('file')

重構一下

上面的 if else 不是很優雅?若是有更多中 logger 類型添加起來很麻煩?那咱們可使用對象來映射一下,從而拋棄 if else,同時添加一個 logger 選項。

// logger/index.js
import ConsoleLogger from './console.js'
import FileLogger from './file.js'

const loggerMap = {
    console: ConsoleLogger,
    file: FileLogger
}
// 可選參數通常放在最後面
function createLogger(options, type = 'console') {
    const Logger = loggerMap[type]
    if (Logger) {
        return new Logger(options)
    }
    throw new Error(`Logger type not found: ${type}`)
}
上面這種封裝的方式,其實也符合 SOLID 原則中的 開閉原則,即 對擴展開放,對修改關閉,每當咱們添加一種 logger 類型時,只須要新增一個文件,而後將構造器註冊進 loggerMap 中便可。而外面的使用方式都是不變的,這樣就用最少的修改完成了功能的新增,是否是很棒呀~

總結

下面咱們來回顧一下工廠模式的優勢:

  • 動態建立對象:能夠用於須要在 運行時 肯定對象類型的狀況。
  • 抽象:封裝了對象建立的細節,用戶不會接觸到對象的構造器,只須要告訴工廠須要哪一種對象。
  • 可用性 / 可維護性:將類似的對象用一個工廠管理,提供統一的建立接口,知足 開閉原則,使咱們能夠輕鬆添加多種類型的對象,而無需修改大量代碼。

好啦~!工廠模式就介紹到這裏啦~ 下次咱們講一講裝飾器模式~

參考內容


本文首發於公衆號:碼力全開(codingonfire)

本文隨意轉載哈,註明原文連接便可,公號文章轉載聯繫我開白名單就好~

codingonfire.jpg

相關文章
相關標籤/搜索