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()
// .......
從上面這個最最簡單的例子裡可以得出如下結論:
- 享元模式是根據實際情況的一種優化方案,如果把上例中改成,小明借閱《A》,《B》,《C》…我們可以得出,這個學校非常窮,只有一個學生,因此我們需要抽離的狀態是學生,而不是書本。
- 享元模式需要根據實際情況抽離外部狀態,保留內部狀態(可共享)。
享元模式根本沒什麼軟用
為什麼我認為享元模式沒什麼軟用
什麼樣的人可以認為享元模式沒什麼軟用。
- 把迭代器用的非常熟練的人
- 把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節約資源!