1. 程式人生 > 其它 >JavaScript設計模式(9)—— 享元模式

JavaScript設計模式(9)—— 享元模式

技術標籤:JavaScript設計模式

享元模式=節約資源模式

享元模式,顧名思義,就是分享“物件”的一個模式。
例如學校裡的圖書館,可能每種型別的書只有十幾本,但是卻能讓一代又一代的學生都能看上這些書,這裡就用到了享元模式。
通過借閱書籍並歸還的例子我們可以得出結論:享元模式是一種節約資源的模式。

最最簡單的例子

在前端程式碼層面,我們通常會建立一些相似的物件來解決相似的問題。
下面我們把圖書館的例子翻譯成程式碼來介紹享元模式。
如:A同學借閱《設計模式》,B同學借閱《設計模式》,C同學借閱《設計模式》,A同學借閱《模式設計》…

class Library{
   constructor
(who,book){ this.who = who this.book = book } borrowBook(){ console.log(this.who + '借' + this.book) } returnBook(){ console.log(this.who + '還' + this.book) } } const A = new Library('小明','《設計模式》') A.borrowBook() A.returnBook() const B = new Library
('大明','《設計模式》') B.borrowBook() B.returnBook() const C = new Library('忠明','《設計模式》') C.borrowBook() C.returnBook() const D = new Library('黃曉明','《設計模式》') D.borrowBook() D.returnBook() // .......

從上面的程式碼中我們可以看到,這個圖書館非常窮,只有一本設計模式,其他人借來借去也只有這“一本”書,因此我們可以通過享元模式把書這個狀態抽離出來。

 class Book{
   constructor(book){
        this
.book = book } borrowBook(){ console.log(this.who + '借' + this.book) } returnBook(){ console.log(this.who + '還' + this.book) } } const A = new Book('《設計模式》') A.who = '黃曉明' A.borrowBook() A.returnBook() A.who = '小明' A.borrowBook() A.returnBook() // .......

從上面這個最最簡單的例子裡可以得出如下結論:

  1. 享元模式是根據實際情況的一種優化方案,如果把上例中改成,小明借閱《A》,《B》,《C》…我們可以得出,這個學校非常窮,只有一個學生,因此我們需要抽離的狀態是學生,而不是書本。
  2. 享元模式需要根據實際情況抽離外部狀態,保留內部狀態(可共享)。
  3. 享元模式根本沒什麼軟用

為什麼我認為享元模式沒什麼軟用

什麼樣的人可以認為享元模式沒什麼軟用。

  1. 把迭代器用的非常熟練的人
  2. 把1條件裡的迭代器改成享元模式同樣成立的人

其實我們很容易從最簡單的例子裡看出來,享元模式根本沒什麼實際內容,他只是對記憶體佔用的一種優化而已,所謂優化,就是想得到的人永遠想得到,他認為剝離外部狀態是一件理所應當的事情,當他發現某個狀態會導致大量相似物件被建立的時候,他自然而然都想把這個狀態剝離出來了。所以說,這個模式也就是所謂的:給你寫的程式碼取個好名字模式。

真正的享元模式

我認為真正的享元模式應當是“沒有內部狀態的享元”(原著中也有提及)。
依舊以現實中的例子為例,在初學Vue時我們用v-for迴圈模板的時候,經常會遇到警告,當然現在我們知道了,v-for迴圈的dom節點必須要有key值,且key儘量保持唯一。那麼Vue為什麼需要一個唯一key值吶?自己去百度原因,我憑空猜測原因大概如下。

由於Vue是一套以資料驅動模板更新的框架,當資料更新的時候,Vue需要通過一系列計算重新得到大量模板的字串,這個現象在陣列迴圈渲染的時候表現得尤為嚴重(Vue3.x細化了這部分的工作,具體可參考Vue3.x說明文件)。因此Vue對這部分迴圈渲染的資料做了優化工作,關鍵就在於key值更新,極簡版程式碼如下。

class Dom {
   static commonDom = []
    constructor(){}
    cmpDom(key){
        if(Dom.commonDom.indexOf(key)!==-1){
            console.log('key已經存在')
            // return 一箇舊的dom
        }else{
            Dom.commonDom.push(key)
            // 儲存一個新的dom
        }
    }
}
let dom = new Dom()
dom.cmpDom(1)
dom.cmpDom(2)
dom.cmpDom(1)

當一個dom元素的key值已經被儲存後,就可以繼續拿出來用,如果一個dom元素的key值和之前的key重複,就return一個重複的dom給他,當然Vue實際不是這麼操作的,我這裡只是單純為了重複利用key值相同的dom。

細心(仔細看了上面垃圾程式碼)的小夥伴已經發現了,這裡並沒有所謂的物件複用啊,只是減少了commonDom陣列的長度,複用了裡面的元素而已,為什麼也叫享元模式吶?

那說明你的理解還沒到胃,享元模式的核心是節約資源!
敲重點!是分享and節約資源!