本文版權歸博客園和作者吳雙本人共同所有,轉載和爬蟲必須注明原文地址 www.cnblogs.com/tdws
工廠模式和抽象工廠在後台代碼中的使用,相信你一定非常熟悉,所以關於概念的東西也用不著我多說。你可以用其做為類與類之間,層與層之間的解耦。工廠模式沒有什麼難點,在JS中其實思想也是一樣的,所以廢話不多說,直接上實踐的場景和代碼。
1.最近的項目的登陸使用了Owin認證,所以token必須找好地方進行存儲,鑒於token需要在請求API資源的時候放到請求頭的Authorization當中,以便在進入WebAPI前進行身份驗證。所以我不想在主流浏覽器中的cookie中存儲token,因為這樣一來,每次Cookie中帶一份token,Authorization中又帶一份token.多傳輸一次不說,還讓人感到很low.這麼 這麼low的行為,你忍心使用嗎。所以我希望把token存儲於localStorage當中。那麼問題來了,不支持H5的浏覽器怎麼辦?
2.為了將來把所有前端資源置於CDN, 前端僅擁有html,css和js。頁面加載到浏覽器客戶端後,所有動態資源走AJAX,並且所有資源均跨域。那麼問題又來了,跨域很容易解決,在IE8,IE9這種默認關閉跨域功能的浏覽器怎麼辦?
我通常會給應用定義一個全局Application.js。其中大概包括如下內容。 先上整體代碼結構,供參考


為了解決上述兩個問題,所以引入工廠模式,在工廠中創建對象,工廠中根據不同浏覽器類型,創建不同對象。
也就是說在解決問題一上,在浏覽器支持H5的時候,存儲token於localStorage。在不支持h5的浏覽器中還是存於cookie.
所以產生了兩個JS對象,CookieStorageUtil對象,LocalStorageUtil對象。並且他們應該實現相同的“接口”,在這裡我沒有使用JS代碼來模仿接口,而是采用注釋的形式,標注兩個對象需要實現相同的接口,實現接口中的兩個方法write()和get()。並規范代碼,下劃線開頭的為私有方法,這樣一來今後修改內部代碼的時候,私有方法隨便改,對外部暴露的方法名稱不變就好,是不是有點像後台的面向接口編程呢?其實JS也是一樣的。再多費一句話,如果我不使用JS的function模擬類的話,是無法達到真正的方法私有,所以如果有人調用下劃線'_'開頭的私有方法,在今後私有方法有變動的時候影響了功能,那就不是我的鍋咯?
還是上代碼靠譜:
1 /**
2 * Storage Factory -Author 吳雙 cnblogs.com/tdws
3 */
4 StorageUtilManager: new Object({
5 createStorageUtil: function () {
6 if (window.applicationCache) {
7 return AppUtil.LocalStorageUtil;
8 } else {
9 return AppUtil.CookieStorageUtil;
10 }
11 }
12 }),
13 /**
14 * implement Storage -Author 吳雙
15 * write()
16 * get()
17 */
18 CookieStorageUtil: {
19 write: function (key, dataObj) {
20 this._clearCookie(key);
21 //寫入的字符串
22 var dataObjStr = JSON.stringify(dataObj);
23 this._setCookie(key, dataObjStr, 15);
24 },
25 get: function (key) {
26 return this._getCookie(key);
27 },
28 _setCookie: function (cname, cvalue, exdays) {
29 var d = new Date();
30 d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
31 var expires = "expires=" + d.toUTCString();
32 var path = "path=/";
33 document.cookie = cname + "=" + cvalue + "; " + expires + "; " + path;
34 },
35 _getCookie: function (cname) {
36 var name = cname + "=";
37 var ca = document.cookie.split(';');
38 for (var i = 0; i < ca.length; i++) {
39 var c = ca[i];
40 while (c.charAt(0) == ' ') c = c.substring(1);
41 if (c.indexOf(name) != -1) return c.substring(name.length, c.length);
42 }
43 return null;
44 },
45 _clearCookie: function (key) {
46 this._setCookie(key, "", -1);
47 }
48 },
49 /**
50 * implement Storage cnblogs.com/tdws
51 * write()
52 * get()
53 */
54 LocalStorageUtil: {
55 write: function (key, dataObj) {
56 this._writeLocalStorage(key, dataObj);
57 },
58 get: function (key) {
59 return this._getFromLocalStorage(key);
60 },
61 _writeLocalStorage: function (key, dataObj) {
62 var localStorage = window.localStorage;
63 localStorage.removeItem(key);
64 //對象轉化為字符串,將objStr按正常的方式存入localStorage中
65 var dataObjStr = JSON.stringify(dataObj);
66 localStorage.setItem(key, dataObjStr);
67 },
68 _getFromLocalStorage: function (key) {
69 var localStorage = window.localStorage;
70 return localStorage.getItem(key);
71 },
72 _removeLocalStorage: function (key) {
73 var localStorage = window.localStorage;
74 localStorage.removeItem(key);
75 }
76 }
這樣第二個問題也得到了解決,在不支持跨域的浏覽器創建XDomainRequest對象來做請求,兩個HttpUtil對象依然實現相同的接口中的方法。在這個跨域問題上,推薦使用gayhub中的一個1.8k的JS https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest
對了,為了避免使用工廠模式,使代碼調用復雜,我們可以簡化JS
AppUtil.currentHttpUtil = AppUtil.HttpUtilManager.createHttpUtil();
所以有了這樣的方式,問題平滑的解決了,兩個StorageUtil與調用方,通過工廠StorageUtilManager完成解耦。可能你看完代碼後說,不就是多了一個Manager嗎?這也很簡單啊,是啊,就是這麼簡單,這就是設計模式,它僅僅是前人的經驗模式,它更平滑的解決我們的實際問題。
如果我的點滴分享對你有點滴幫助,歡迎點擊下方紅色按鈕關注,我將持續輸出分享。也歡迎為你自己也為我點贊支持。
—— 保持學習,謹記謙虛。不端不裝,有趣有夢。