【讀書】JavaScript 設計模式與開發實踐

2016.08.30node

 

JavaScript 設計模式與開發實踐》 曾探 人民郵電出版社 20165月第1程序員

p13算法

找到變化的部分並封裝之,以使得容易替換;而剩下的就是不變的部分。編程

 

P49設計模式

函數柯里化(currying)的做用是屢次收集參數,而後做爲數組傳給處理函數再一次執行。數組

其意義在於預處理——將預處理的流程放到一個函數裏會更爲清晰可控。緩存

P57數據結構

惰性加載函數閉包

在函數內部重寫引用函數的外部變量的引用,從而在第一次調用此變量後,此變量就指向新的正確的函數。mvc

p84

這裏的errorMsg不該該包含在strategies的項裏。這些項只要返回true/false就好,msg關他們什麼事啊!

也許是msg要根據strategie而變化吧。

P86

策略模式的目的是將算法獨立出代碼的執行部分(content),使計算的代碼可複用、實現靈活。

關鍵點在於看出何爲策略的最低依賴描述、考慮如何從content進入算法中。

P89

關於代理模式,所謂代理是在訪問者-被訪問者這二者間的代理者。被訪問者提供了一些接口供任意人訪問。這些接口在某些狀況下不該被調用或應以另外一個形式被調用,這時爲了保證接口內的職責單一性,應該隔一層調用這個接口;這一層用於處理那些特定狀況,決定如何調用接口,這層就是代理。

代理模式的目的是爲了保持接口的職責單一性。

代理模式的主要特色是代理者與被代理者(即被訪問者)擁有職責一致的接口,通常接口名稱也一致。

因爲須要處理的情形不少,代理的模式也各類各樣:

保護代理: 用於接口有不一樣訪問權限的狀況

虛擬代理: 目的是延遲對接口的訪問,到有必要時再訪問

緩存代理: 存儲接口結果,參數一致時不調用接口直接返回已存結果。

等等。也不是說使用了虛擬代理就不能使用保護代理,以上列表只是說明這些情景下須要代理。

P93

單一職責原則指的是:就一個類(也包括對象與函數)而言,應該僅有一個引發它變化的緣由。若是一個類承擔了多項職責,就意味着這個類將變得巨大,引發它變化的緣由可能會有多個。

職責被定義爲引發變化的緣由。當一個類承擔多個職責時,因爲其高耦合性,一個職責的處理可能會影響到另外一個職責的處理。

代理層能承擔部分職責,使接口職責單一。

p124

發佈-訂閱模式推模型的問題在於:訂閱者收到的數據是由發佈者決定的。

拉模型的問題在於發佈者可能會變成一個公開的對象。

首先,選用拉模型。

1. 發佈時傳一個對象,此對象上擁有一系列接口供訂閱者獲取數據。可能須要用代理模式。

2. 在訂閱時傳入一些函數,這些函數將在結果上調用並返回調用結果(太複雜)。

發佈-訂閱模式裏也用到了策略模式。

P131

命令模式的意義在於將職責分到三部分中:命令者-命令-執行者。另外一個更重要的意義是命令將變成可存儲、調用的數據。

 

 

p132

疑點在於這裏的演示,命令moveCommand與執行者animate是綁定的,也就是說moveCommand不能用於命令animate2。若是有多個執行者,必須生成多個對應的命令。

其實能夠實現成moveCommand.execute(animate2)

不過仔細想一想假如執行者不止animate2還有xxx2的話?多執行者這種狀況能夠有的吧?

這樣子可能就是實現成:

var MoveCommand = function(receiver, pos){

......

this.receivers = [receiver]

}

MoveCommand.prototype.execute = function(){

if(!arguments.length){

this._execute.apply(this, this.receivers)

} else {

this._execute.apply(this, arguments)

}

}

MoveCommand.prototype._execute = function(receiver){

receiver.start......

}

命令裏包含執行者也有好處,存儲命令就能存儲執行者了。

 

p132

組合模式的關鍵是接口一致。

p151

模板方法模式由兩部分結構組成,第一部分是抽象父類,第二部分是具體的實現子類。一般在抽象父類中封裝了子類的算法框架。,包括實現一些公共方法以及封裝子類中全部方法的執行順序。子類經過這個抽象類,也繼承了整個算法結構,而且能夠選擇重寫父類的方法。

p160

鉤子方法爲何必定要是方法呢?

由於能夠動態獲得結果,只是要怎樣讓外部能改變到鉤子是個問題。

  1. 經過this訪問。也就是這裏的實現。

2. 做爲閉包暴露鉤子。

 

p173

假若有2000個文件,uploadDatabase里根本就會存2000個對象。只不過不是2000upload對象。

因此我認爲享元模式的意義在於將數據與模板分離,從而共享了一個結構、一些方法。

須要使用一個對象時,拿數據填模板,就獲得指定結構的對象與可用的方法。

而這裏所謂的有多少個內部狀態,就有多少個共享對象,內部狀態指的是模板,共享對象指的是模板的相應數據化結果(具體到這裏的代碼就是flyWeightObj,而不是Upload構造器。Upload構造器說到底跟享元模式無關,只是的抽象類,是內部狀態的抽象。12.6.1有例證)。

 

因爲將數據分離,因此在本書的實現中,數據須要一個UploadManager來管理,併爲模板裏的方法提供一個UploadManager.setExternalState以讀取數據填充到指定對象(就是模板自己)

 

關於這個實現,我以爲這裏flyWeightObj.delFile(id)uploadManager.setExternalState(id, this)同時出現就很差,相互調用感受就很差。(應該沒有相互引用)

是否是改爲flyWeightObj.delFile(id); this.setExternalState(id, flyWeightObj); 會比較好?

貌似他這麼作也無不妥,在flyWeightObj.delFile裏先將數據填充到自己上再刪除數據,是一種合理的作法。畢竟delFile可能會被屢次調用,總不能每次調用前都寫一句setExternalState吧?

 

若是不須要存在,那就沒有必要使用享元模式。

 

p185

職責鏈模式的最大優勢就是解耦了請求發送者和N個接受者之間的複雜關係,因爲不知道鏈中的哪一個節點能夠處理你發出的請求,因此你只需把請求傳遞給第一個節點便可。

本書實現的職責鏈的問題在於程序員不知道鏈的具體模樣。因此A-B-D,我要往B後面插個C就必須知道BD的引用,並修改它們的nextNode屬性。

能夠var chainCtrl = new ChainCtrl(); var A = chainCtrl.cteateAndAppendNode(fnA), B = ......; var C = chainCtrl.createNode(fnC); chainCtrl.insertAfter(C, B);

以上的具體實現裏,不只要維護一個存在ChainCtrl內部的數組,仍須要實現node.nextNode屬性,這樣纔可以調用B.next()以跳過AB開始執行職責鏈。

 

p187

這裏提到AOP(面向切面編程)

AOP解決的問題是但願在函數執行前或執行後插入代碼又不但願改動原函數。(若是但願在函數執行中某個位置插入代碼,恐怕只能使用鉤子)

AOP的關鍵是用一個函數調用原函數並代替原函數被使用。

順便一說,LISP裏自然實現AOP

p189

中介者模式解決代碼塊間聯繫太多,耦合強的問題。(就像在心臟旁邊拆掉一根毛細血管通常,即便一點很小的修改也必須當心翼翼)

 

p195

這裏在構造player時傳入teamColor我認爲是不對的。」team」是一個外部狀態而不是player所固有的東西,應該隔一層在playerFactory這個函數裏調用setTeam(player)player設置屬性。要否則之後需求改爲當一個隊伍滿2人時,新的玩家將進入不滿員隊伍或新建隊伍,這時候勢必要:

  1. Player構造器加判斷邏輯。這固然不行。
  2. Player構造器不直接加判斷邏輯而是使用鉤子。我認爲這也半斤八兩,畢竟要調用與team相關的外部接口。
  3. 使用AOP,替換掉Player。可替換掉構造器貌似不妥。

仍是移除在Player裏對teamColor屬性的設置比較好。這時能夠:

1.playerFactory使用鉤子。

2.playerFactory這個函數裏調用setTeam(player)

 

p195

此處Player.prototype.die 等方法裏調用了playerDirector.ReceiveMessage,這樣就依賴了中介者模式的playerDirector,往後若是想換個模式勢必要改動這裏的代碼。建議隔一層。

要這麼說,全部調用外部接口的都應隔一層了。

p198

這裏關於掉線的處理有問題,假如先dieremove,由於remove裏沒有檢查,另外一方就不能得到勝利了。

能夠考慮使用AOP

 

p199

說到購買商品的例子,能不能創造一種流程模式?將流程放到數組裏,調用next()則進入下一個流程,調用jump(fn)則跳到fn對應的流程。

還有就是想說,這裏可使用mvc的理念。在頁面上操做,而後進入中介者,而後中介者處理一個數據結構,而後中介者調用一個渲染函數根據這個數據結構對頁面進行渲染。

問題在於如何只渲染須要渲染的內容。

 

p206

這裏的changed太過臃腫,耦合度也高,應該把if-else分割成函數放到一個obj裏,而後在changed裏遍歷obj的成員並用職責鏈模式將它們鏈接起來。

而剩餘部分,或許也能夠分割成函數並使用AOP鏈接。

p208

過分抽象會使得無形狀,不直觀。

 

p211

裝飾者模式的意圖是減小子類與實例的數量。

同名調用同名聽起來有點像代理模式。

就邏輯業務上二者的區別,代理者的業務與被代理者的業務是相關的,裝飾者與被裝飾者的業務能夠是毫無關聯的。

就實現上而言,代理者是擁有被代理者同名方法的一個對象(或函數);裝飾者是在類A的原型方法中調用另外一個類B建立的實例的方法,最後調用new A()獲得一個實例,或者使用AOP替換原方法。

若是被裝飾者是單例,裝飾者模式是會改變被裝飾者的,代理模式則能夠不改變它。

相關文章
相關標籤/搜索