JavaScript設計模式之單例模式實例_javascript技巧
《Practical Common Lisp》的作者 Peter Seibel 曾說,如果你需要一種模式,那一定是哪裡出了問題。他所說的問題是指因為語言的天生缺陷,所以不得不去尋求和總結一個通用的解決方案。
不管是弱型或強型,靜態或動態語言,命令式或說明式語言、每種語言都有天生的優缺點。一個牙買加運動員, 在短跑甚至拳擊方面有一些優勢,在練瑜珈上就欠缺一些。
術士和暗影牧師很容易成為一個出色的輔助,而一個背著梅肯滿地圖飛的敵法就會略顯尷尬。 換到程式中, 靜態語言裡可能需要花很多功夫來實現裝飾者,而js由於能隨時往對像上面扔方法,以至於裝飾者模式在js裡成了雞肋。
講Javascript 設計模式的書還比較少,《Pro javaScript Design Patterns》是比較經典的一本,但是它裡面的例子舉得比較囉嗦,所以結合我在工作中寫過的程式碼,把我的理解總結一下。如果我的理解出現了偏差,請不吝指正。
一、單例模式
單例模式的定義是產生一個類別的唯一實例,但js本身是一種「無類別」語言。很多講js設計模式的文章把{}當成一個單例來使用也勉強說得通。因為js產生物件的方式有很多種,我們來看下另一種更有意義的單例。
有這樣一個常見的需求,點擊某個按鈕的時候需要在頁面彈出一個遮罩層。例如web.qq.com點選登入的時候.
這個產生灰色背景遮罩層的程式碼是很好寫的.
var createMask = function(){
return document,body.appendChild( document.createElement(div) );
}
$( ‘button' ).click( function(){
Var mask = createMask();
mask.show();
})
問題是, 這個遮罩層是全域唯一的, 那麼每次調用createMask都會創建一個新的div, 雖然可以在隱藏遮罩層的把它remove掉. 但顯然這樣做不合理.
再看下第二種方案, 在頁面的一開始就創建好這個div. 然後用一個變數引用它.
var mask = document.body.appendChild( document.createElement( ”div' ) );
$( ”button' ).click( function(){
mask.show();
} )
這樣確實在頁面只會創建一個遮罩層div, 但是另外一個問題隨之而來, 也許我們永遠都不需要這個遮罩層, 那又浪費掉一個div, 對dom節點的任何操作都應該要很吝嗇.
如果可以藉助一個變數. 來判斷是否已經建立過div呢?
var mask;
var createMask = function(){
if ( mask ) return mask;
else{
mask = document,body.appendChild( document.createElement(div) );
return mask;
}
}
看起來不錯, 到這裡的確完成了一個產生單列物件的函數. 我們再仔細看這段程式碼有什麼不妥.
首先這個函數是存在一定副作用的, 函數體內改變了外界變量mask的引用, 在多人協作的項目中, createMask是個不安全的函數. 另一方面, mask這個全局變量並不是非需不可. 再來改進一下.
var createMask = function(){
var mask;
return function(){
return mask || ( mask = document.body.appendChild( document.createElement(‘div') ) )
}
}()
用了個簡單的閉包把變數mask包起來, 至少對於createMask函數來講, 它是封閉的.
可能看到這裡, 會覺得單例模式也太簡單了. 的確一些設計模式都是非常簡單的, 即使從沒關注過設計模式的概念, 在平時的代碼中也不知不覺用到了一些設計模式. 就像多年前我明白老漢推車是什麼回事的時候也想過尼瑪原來這就是老漢推車.
GOF裡的23種設計模式, 也是在軟體開發中早就存在並反覆使用的模式. 如果程式設計師沒有明確意識到他使用過某些模式, 那麼下次他也許會錯過更合適的設計(這段話來自《松本行弘的程序世界》).
再回來正題, 前面那個單例還是有缺點. 它只能用於創建遮罩層. 假如我又需要寫一個函數, 用來創建一個唯一的xhr對象呢? 能不能找到一個通用的singleton包裝器.
js中函數是第一型, 表示函數也可以當參數傳遞. 看看最終的程式碼.
var singleton = function( fn ){
var result;
return function(){
return result || ( result = fn .apply( this, arguments ) );
}
}
var createMask = singleton( function(){
return document.body.appendChild( document.createElement(‘div') );
})
用一個變數來保存第一次的回傳值, 如果它已經被賦值過, 那麼在以後的呼叫中優先返回該變數. 而真正創建遮罩層的程式碼是透過回呼函數的方式傳人到singleton包裝器中的. 這種方式其實叫橋接模式. 關於橋接模式, 放在後面一點點來說.
然而singleton函數也不是完美的, 它總是需要一個變數result來寄存div的引用. 遺憾的是js的函數式特性還不足以完全的消除聲明和語句.

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

在Java框架中,設計模式和架構模式的區別在於:設計模式定義了在軟體設計中解決常見問題的抽象解決方案,專注於類別和物件之間的交互,例如工廠模式。架構模式定義了系統結構和模組之間的關係,關注系統元件的組織和交互,如分層架構。

裝飾器模式是一種結構型設計模式,允許動態添加物件功能,無需修改原始類別。它透過抽象組件、具體組件、抽象裝飾器和具體裝飾器的協作實現,可以靈活擴展類別功能,滿足變化的需求。範例中,將牛奶和摩卡裝飾器添加到Espresso,總價為2.29美元,展示了裝飾器模式在動態修改物件行為方面的強大功能。

1.工廠模式:分離物件創建和業務邏輯,透過工廠類別建立指定類型的物件。 2.觀察者模式:允許主題物件通知觀察者物件其狀態更改,實現鬆散耦合和觀察者模式。

設計模式透過提供可重複使用和可擴展的解決方案來解決程式碼維護難題:觀察者模式:允許物件訂閱事件,並在事件發生時收到通知。工廠模式:提供了一種創建物件的集中式方式,而無需依賴特定類別。單例模式:確保一個類別只有一個實例,用於建立全域可存取的物件。

TDD用於編寫高品質PHP程式碼,步驟包括:編寫測試案例,描述預期功能並使其失敗。編寫程式碼,僅使測試案例通過,無需過度優化或詳細設計。測試案例通過後,優化和重構程式碼以提高可讀性、可維護性和可擴展性。

適配器模式是一種結構型設計模式,允許不相容物件協同工作,它將一個介面轉換為另一個,使物件能夠順利互動。物件適配器透過建立包含被適配器對象的適配器對象,並實現目標接口,實現適配器模式。在一個實戰案例中,透過適配器模式,客戶端(如MediaPlayer)可以播放高級格式的媒體(如VLC),儘管本身僅支援普通媒體格式(如MP3)。

Guice框架應用了多項設計模式,包括:單例模式:透過@Singleton註解確保類別只有一個實例。工廠方法模式:透過@Provides註解建立工廠方法,在依賴注入時取得物件實例。策略模式:將演算法封裝成不同策略類,透過@Named註解指定具體策略。

Java框架中使用設計模式的優點包括:程式碼可讀性、可維護性和可擴充性增強。缺點包括:過度使用導致複雜性、效能開銷以及學習曲線陡峭。實戰案例:代理模式用於延遲載入物件。明智地使用設計模式可充分利用其優勢並最小化缺點。
