摘要:模式迭代器模式顧名思義,迭代器可以將對于一個聚合對象內部元素的訪問與業務邏輯分離開。模式組合模式組合模式將對象組合成樹形結構,以表示層級結構。重點是,葉結點與中間結點有統一借口。本文總結自設計模式與開發實踐,曾探著
模式1 - 單例模式
單例模式的核心是確保只有一個實例,并且提供全局訪問。
特點:
滿足“單一職責原則” : 使用代理模式,不在構造函數中判斷是否已經創建過該單例;
滿足惰性原則
應用:
彈出登陸窗口。
實例:
var getSingle = function (fn) { var res; return function() { return res || (res = fn.apply(this, arguments)); } } var createPopup() { var div = document.createElement("div"); div.innerHTML = "Login window"; div.style.display = "none"; document.body.appendChild(div); return div; } var createLoginPopup = getSingle(createPopup); //create popup div here by using a given function, 滿足兩個原則 document.getElementById("loginBt").onclick = function() { var popup = createLoginPopup(); pop.style.display = "block"; }
模式2 - 策略模式
定義一個個可以相互替換的算法,并且把他們封裝起來。
特點:
符合開放-封閉原則 : 要修改使用的算法時不用深入函數內部進行修改,只需修改策略類;
將算法的實現與使用分離開,提高算法復用性;
通過組合、委托和多態避免多重條件選擇語句;
應用:
動畫實現不同的緩動效果。
一般分為兩個部分:策略類于環境類。策略類用于封裝各種算法,并且負責具體的計算過程; 環境類負責接收用戶的請求,并且把請求委托給某一個策略類。因為各個策略類實現的算法和計算的結果不同,而環境類調用策略類的方法卻是相同的,這就體現了多態性。要想實現不同的算法,只需要替換環境類中的策略類即可。
在js中,我們不必構造策略類,可直接使用函數作為策略對象。
示例:
var strategies = { "s1": function() { //algo 1 }, "s2": function() { //algo 2 }, "s3": function() { //algo 3 } } var someContext = new SomeConext(); someContext.start("s1"); //using s1 to calculate //someContext.add("s1"); or add s1 as a rule for validation
模式3 - 代理模式
代理就像一個經紀人,當用戶不方便直接訪問某個對象或者需要對訪問進行一些過濾/加工時,可以通過代理來進行對象訪問。代理會對請求進行一些處理,然后再將請求傳遞給本體。
一般分為保護代理和虛擬代理:
保護代理負責過濾掉一些請求;
虛擬代理則是將一些花銷比較大的操作延遲到真正他的時候再去創建,例如new一個對象。
特點:
保證對象符合單一職責原則;
應用:
圖片預加載, 合并http請求, 惰性加載, 緩存代理(避免重復計算,可以寫一個通用的緩存對象(其實就是一個閉包),將高階函數作為參數傳入)。
模式4 - 迭代器模式
顧名思義,迭代器可以將對于一個聚合對象內部元素的訪問與業務邏輯分離開。
一般分為內部迭代器和外部迭代器:
內部迭代器只需一次初始調用,不需要關心迭代器的內部實現;
外部迭代器需要顯式地請求下一個元素,因此可以手工控制迭代過程和順序,例如調用iterator.next();
無論是哪種迭代器,只要聚合對象有length屬性并且可以通過下標訪問,那么就可以被迭代。因此類數組對象及字面量對象(用for in)都可以。
絕大部分語言都內置了迭代器。
應用:
可以通過添加終止條件來中斷迭代:在callback函數中判斷,如果return值為false,則通過break跳出迭代循環。
由此可以設計根據瀏覽器類型創建的返回對象,按優先級一個個迭代。
模式5 - 訂閱發布模式
將許多對象弱耦合起來,當一個對象的狀態發生變化時,所有訂閱了該變化的對象都會收到通知。
DOM事件是典型的訂閱發布模式,同時我們還可以自定義事件:
var event = { clients : {}, listen : function (signal,fn){ if(!this.clients[signal]) { this.clients[signal] = []; } this.clients[signal].push(fn); }, trigger: function (arguments){ //not only trigger the event, but also send some data var sig = Array.prototype.shift.call(arguments); fns = this.clients[sig]; if(!fns || fns.length === 0) return false; for(var i = 0; i < fns.length; i++) { var fn = fns[i]; fn.apply(this, arguments); } }, remove: function (signal,fn){ var fns = this.clients[signal]; if(!fns) return false; if(!fn) { //remove all fns delete this.clients[signal]; } else { for(var i = 0; i可以通過離線消息棧來保存沒有被訂閱的但是發生了的事件,等到有人訂閱再依次取出執行。
應用:
網站登錄-當用戶登錄成功并且ajax返回數據后,trigger事件,需要用到用戶數據的渲染模塊訂閱該事件。模式6-命令模式
可以解決請求發送者和請求接受者之間的耦合關系。實際上,我們只需要調用command對象中的execute方法就行,他會自動調用命令接收者對應的命令。
示例:
var tv = { open: function() { console.log("open tv"); }, close: function() { console.log("turn off tv"); }, nextChannel: function() { console.log("next channel"); } } //相當于我把receiver的一些可用操作封裝到command對象里了,并且提供了統一的接口 var openTVCmd = function(receiver) { return { execute: function(){ receiver.open(); }, undo : function() { //go to previous channel } } } var btn1 = document.getElementById("btn1"); var btn2 = document.getElementById("btn2"); var setCmd = function(button, cmd) { button.onclick = function(){ cmd.execute(); } } var opentvcmd = new openTVCmd(); setCmd(btn1, opentvcmd); btn2.onclick = function(){ //undo command opentvcmd.undo(); }應用:
可實現命令的撤銷和重做,只需紀錄一個oldState或者使用一個緩存來存放歷史命令;
可實現命令隊列,將command對象壓入堆棧,只需依次調用他們的execute函數,由此可實現宏命令;
可分為智能命令和傻瓜命令:
1.智能命令不需要知道receiver,可自己完成請求,代碼上類似策略模式,但目的不同;
2.傻瓜命令則只負責將請求傳遞給真正的receiver。模式7-組合模式
組合模式將對象組合成樹形結構,以表示層級結構。借助于對象的多態性,它使得用戶可以統一地對待組合對象(單個對象的組合)和單個對象。
應用:
可實現宏命令,只需要調用根結點的execute,程序會自動遍歷整棵樹并依次執行各中間節點和葉結點的execute函數。重點是,葉結點與中間結點有統一借口。
可用來模擬文件和文件夾層級結構:
示例:
var Folder = function(name) { this.name = name; this.files = []; } Folder.prototype.add = function(file) { this.files.push(file); } Folder.prototype.scan = function() { console.log("begin scanning folder "+ this.name); for(var i=0; i注意,層級1與層級2結點之間并非父子關系,只是因為他們有統一的借口而被聯系在一起。
可以對這兩種結點建立雙向映射,即使文件1里面含有其父結點的引用,這樣子在刪除一個文件時就需要將其在其父結點的files中刪除。組合模式使得用戶可以忽略組合對象和單個對象的差異而統一對待,但這也會使得每個對象看上去都差不多,增加代碼理解的難度。
P.s. 本文總結自《JavaScript設計模式與開發實踐》,曾探著
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/91264.html
摘要:設計模式是以面向對象編程為基礎的,的面向對象編程和傳統的的面向對象編程有些差別,這讓我一開始接觸的時候感到十分痛苦,但是這只能靠自己慢慢積累慢慢思考。想繼續了解設計模式必須要先搞懂面向對象編程,否則只會讓你自己更痛苦。 JavaScript 中的構造函數 學習總結。知識只有分享才有存在的意義。 是時候替換你的 for 循環大法了~ 《小分享》JavaScript中數組的那些迭代方法~ ...
摘要:首先,需要來理清一些基礎的計算機編程概念編程哲學與設計模式計算機編程理念源自于對現實抽象的哲學思考,面向對象編程是其一種思維方式,與它并駕齊驅的是另外兩種思路過程式和函數式編程。 JavaScript 中的原型機制一直以來都被眾多開發者(包括本人)低估甚至忽視了,這是因為絕大多數人沒有想要深刻理解這個機制的內涵,以及越來越多的開發者缺乏計算機編程相關的基礎知識。對于這樣的開發者來說 J...
摘要:函數式編程前端掘金引言面向對象編程一直以來都是中的主導范式。函數式編程是一種強調減少對程序外部狀態產生改變的方式。 JavaScript 函數式編程 - 前端 - 掘金引言 面向對象編程一直以來都是JavaScript中的主導范式。JavaScript作為一門多范式編程語言,然而,近幾年,函數式編程越來越多得受到開發者的青睞。函數式編程是一種強調減少對程序外部狀態產生改變的方式。因此,...
摘要:前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點分為新聞熱點開發教程工程實踐深度閱讀開源項目巔峰人生等欄目。背后的故事本文是對于年之間世界發生的大事件的詳細介紹,闡述了從提出到角力到流產的前世今生。 前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點;分為新聞熱點、開發教程、工程實踐、深度閱讀、開源項目、巔峰人生等欄目。歡迎...
摘要:是文檔的一種表示結構。這些任務大部分都是基于它。這個實踐的重點是把你在前端練級攻略第部分中學到的一些東西和結合起來。一旦你進入框架部分,你將更好地理解并使用它們。到目前為止,你一直在使用進行操作。它是在前端系統像今天這樣復雜之前編寫的。 本文是 前端練級攻略 第二部分,第一部分請看下面: 前端練級攻略(第一部分) 在第二部分,我們將重點學習 JavaScript 作為一種獨立的語言,如...
摘要:很多情況下,通常一個人類,即創建了一個具體的對象。對象就是數據,對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍圖或原型。在中,對象通過對類的實體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
閱讀 371·2023-04-25 16:38
閱讀 1482·2021-09-26 09:46
閱讀 3326·2021-09-08 09:35
閱讀 2779·2019-08-30 12:54
閱讀 3249·2019-08-29 17:06
閱讀 1017·2019-08-29 14:06
閱讀 3344·2019-08-29 13:00
閱讀 3466·2019-08-28 17:53