該隨筆的思想原點,應該算是在兩三年前了。當時和一前同事聊天、不知怎得就聊到了Http訪問。
一、我記得他和我說過的第一句話,大概是:有沒有已經封裝好的、比較強大的HttpUtil。也可能是受業務的影響(接口對內)、我當時接觸到的Http訪問,大多比較“規范”,至少有一個接口約束在約定着某些東西,不至於一會傳遞json,返回json, 一會又要傳遞xml,返回xml,甚至更奇葩的是,上傳個文件、返回0或者1。如果真出現這樣的狀態,HttpUtil依然能夠方便、靈活的適應着各種情況、我想這個Util已經絕對強大了。而不巧的是,我同事那里恰恰就是要滿足這樣奇葩的需求(和多個第三方進行系統對接)。
記得當時,面對這個問題時、我的第一意識:模板方法,並且似乎還在哪里見過這樣的使用方式。因為:整個Http訪問的流程無外乎:
1、根據Url創建請求對象,
2、設置請求參數,比如:不使用緩存、設置Header、Cookie、超時時間 等等。
3、發送數據,比如:Post方法。
4、創建響應對象
5、接收數據。
6、獲取響應參數
7、初上述流程之外,無論是作為Util、還是作為一個強大的框架、很有可能還進行異常處理、日志記錄等附加流程。
定義一個算法主干、將步驟的細節實現延遲到子類,使得。在基類中復用代碼,形成一個繼承體系,最終,只需要在最底層的類中、重寫函數處理三件事,一個是提供請求地址,第二個是提供請求數據,第三個是處理響應數據,當然這樣處理、默認認為請求方法已經被封裝了。這么一想,這個方案似乎不錯啊?
但是,如果系統中有成百上千個需要對接的接口,結果會咋樣?成百上千個類? 似乎也可以接受?
再復雜一點,如果請求的數據可能是表單、Json、Xml、文件,而響應的數據也有可能是這些、甚至更多,那么面對這樣的需求,如果繼續使用模板方法會咋樣?仔細想想,繼承可以實現代碼復用、但面對上述的需求,如果只是使用繼承、能實現高效復用嗎(尤其是面對單繼承的情況下)?請注意在這里處理請求數據 和 處理響應數據是兩個變化點、並且是兩個變化點獨立變化,即請求數據可能是模擬的一個表單,而響應數據可能是一段Json、一段Xml、一張Image(驗證碼), 甚至可能是一個文件 或者一個壓縮包(多個文件)。而如果請求數據是Json、Xml 等等格式,響應數據依然有可能是如上的情況。也就說一旦遇到多個變化點獨立變化時,單繼承瞬間就被打回原形了。
再多浪費一點思考的精力,如果將大量的可復用代碼放入基類(訪問權限是受保護的),然后在子類中選擇性進行調用,似乎也可以解決上文提到的“多個變化點獨立變化”的問題,但是那樣一來,基類會極其臃腫,靈活性會大大降低,並且多種數據處理方式之間的耦合性會成指數級上升【這算是一種更失敗的設計】。
回頭瞅一眼,剛開始、模板方法也不錯啊、即便一個對接接口對應一個類,在某種程度上也是可以接受的啊。畢竟每個接口都具有獨立性、單個類進行對應,符合單一職責原則。如果多個接口具有相似性(指的是業務上的相似性),也可以很方便的借助模板方法的繼承體系、只需新建一個Method,便可以搭建成一個簡單工廠模式,以便隱藏掉更多的實現類、達到簡化使用的目的。只是后來由於“多個變化點獨立變化”,才引發了一些問題,如若不然,前者的設計依然可以很好地工作。那么“多個變化點獨立變化”的問題,該怎么解決呢?答:策略,對每一個變化點,單獨使用策略模式。至此、這個比較強大的HttpUtil,算是暫告一段落。至少,在實際應用中,以 模板方法 + 策略模式 這樣的組織方式,構建出來的代碼已經滿足了現有需求,如有其它問題,歡迎留言。
二、當我提出了模板方法之后,我問同事,有什么想法?他的回答是,似乎覺得使用了策略模式之后,模板方法就不需要了,或者說模板方法可以完全被策略模式所替代。並且我當時也有一個錯誤認知,模板方法 = 一組策略模式。在代碼效果上來看,模板方法 和 一組策略模式 確實是可以划等號的,但兩者真的“相等”嗎? 如果相等,那么模板方法似乎沒必要存在了?我們先看一下兩者的意圖吧:
模板方法的意圖:定義一個算法流程,將一些特定步驟的具體實現、延遲到子類。使得可以在不改變算法流程的情況下,通過不同的子類、來實現“定制”流程中的特定的步驟。
策略模式的意圖:使不同的算法可以被相互替換,而不影響客戶端的使用。
在意圖上看,模板方法更加強調:
1)定義一條線(算法流程),線上的多個點是可以變化的(具體實現在子類中完成),線上的多個點一定是會被執行的,並且一定是按照特定流程被執行的。
2)算法流程只有唯一的入口,對於點的訪問是受限的【通常用受保護的虛函數來定義可變點】。
策略模式更注重於: 一個“策略”是一個整體的(完整的)算法,算法是可以被整體替換的。而模板方法只能被替換其中的特定點,算法流程是固定不可變的。
在這樣的細節上看來,模板方法 和 一組策略模式 是不可以划等號的。
三、在這個“古老”的模式——模板方法面前,似乎 “優先使用對象組合,而不是繼承” 的策略模式 很是趾高氣昂?我個人還是覺得、各有優缺,只是各自適應的場景不一樣而已。當遇到“多個變化點獨立變化”時,這時就需要策略模式來救場了,如若不然,原有架構可以很好地進行維護和擴展,那還有必要去大動干戈、非要去找到那個暫時最完美的答案嗎?似乎沒有吧。
四、附參考資料《設計模式精解》: