天天看點

淺談前端當中常見的設計模式

一、什麼是設計模式

定義:設計模式是一套被反複使用的、多數人知曉的、經過分類編目的、代碼設計經驗的總結。在面向對象軟體設計過程中針對特定問題的優雅而簡潔的解決方案。

設計模式遵循一下幾種原則:

1、開閉原則:對擴充開放,對修改關閉

2、單一職責原則:一個類隻負責一個功能領域中的相應職責

3、裡氏代換原則:所有引用基類的地方必須能透明地使用其子類的對象

4、依賴倒轉原則:依賴于抽象,不能依賴于具體實作

5、接口隔離原則:類之間的依賴關系應該建立在最小的接口上

6、合成/聚合複用原則:盡量使用合成/聚合,而不是通過繼承達到複用的目的

7、最少知道原則:一個軟體實體應當盡可能少的與其他實體發生互相作用

二、為什麼要了解設計模式

設計模式說白了就是前輩們對自己代碼經驗的總結,目的是為了讓我們在遇到類似或相同的問題的時候有經驗可以參考或借鑒使用,使得代碼可複用、更容易被他人了解。

1、設計模式可以讓你知道在某些場景下如何設計出适合該場景的架子。如果隻追求去實作一個功能,沒有做其他的考慮,以後需要增加新功能或者做一些改動的時候,可能就會将代碼改的面目全非,難以維護,不熟悉代碼的人接手幹活的話,會出現根本無從下手的問題;

2、如果想要提高自己的能力,去學習一些架構或者庫的源碼的時候,了解設計模式也有助于去了解源碼當中應用到的一些設計思想,幫助自己更好的成長;

三、前端中常見的設計模式

設計模式按照分類分為三大類:建立型模式、結構型模式、行為型模式;總共是有23種設計模式。在這裡我隻想根據我做過的項目經驗和自己學習設計模式過程中的一些了解來談一談前端中常見的幾種設計模式。通過介紹主要思想結合案例的代碼去和大家一起分享以下的幾種設計模式。

1、工廠模式

什麼是工廠模式?工廠模式是用來建立對象的一種最常用的設計模式。我們不暴露建立對象的具體邏輯,而是将邏輯封裝在一個函數中,那麼這個函數就可以被視為一個工廠。說白了就是像工廠一樣重複的産生類似的産品,工廠模式隻需要我們傳入正确的參數,就能生産類似的産品;

生活中的執行個體:我們去飯店吃飯,隻需要知道菜名,飯店後廚就能夠做出相應的菜,而不需要關注具體每道菜的材料、調料以及烹饪方法。

工廠模式的分類:工廠模式根據抽象程度的不同可以分為:

a、簡單工廠

b、工廠方法

c、抽象工廠

工廠模式的優點:我們可以在不動之前原邏輯的基礎上,繼承和拓展新的功能,這樣我們就可以提高效率,之前寫好的功能可以複用,而且可以站在前人的肩膀上,不斷拓展。

在實際的項目中,我們常常需要根據使用者的權限來渲染不同的頁面,進階權限的使用者所擁有的頁面有些是無法被低級權限的使用者所檢視。是以我們可以在不同權限等級使用者的構造函數中儲存該使用者能夠看到的頁面,再根據權限執行個體化使用者。

超級管理者:首頁、活動頁面、資料管理、權限管理
   管理者:首頁、活動頁面、資料管理
   普通使用者:首頁、活動頁面           

function UserFactory(role) {

return new this[role]();

}

//工廠方法函數的原型中設定所有對象的構造函數

UserFactory.prototype = {

superAdmin: function () {

this.name = "超級管理者";
this.auth = ["首頁", "活動", "資料管理", "權限管理"];           

},

admin: function () {

this.name = "管理者";
this.auth = ["首頁", "活動", "資料管理"];           

user: function () {

this.name = "普通使用者";
this.auth = ["首頁", "活動"];           

vipUser: function () {

this.name = "超級心悅會員";
this.auth = ["首頁", "活動", "資料管理", "權限管理", "心悅會員專享福利"];           

};

根據擷取到的使用者角色資訊,直接通過工廠模式,new 一個UserFactory的執行個體出來,擷取到對應的頁面權限直接渲染展示出來。

2、單例模式

什麼是單例模式?限制類執行個體化次數隻能一次,一個類隻有一個執行個體,并且提供可全局通路的點。

單例模式的實作:保證一個類隻有一個執行個體, 一般先判斷執行個體是否存在,如果存在直接傳回, 不存在則先建立再傳回,這樣就可以保證一個類隻有一個執行個體對象。

1、我們前端應用在使用websocket通信的時候,首先會建立一個websocket連接配接但是如果過多的websocket連接配接會占用大量的服務端的資源,是以一個頁面不可能也沒必要初始化多個相同接口的websocket連接配接 ,一個應用當中不管有多少頁面,都可以共享同一個連接配接;

2、項目中引入第三方庫時,重複多次加載庫檔案時,全局隻會執行個體化一個庫對象,如 jQuery,lodash,moment ..., 其實它們的實作理念也是單例模式;

3、當我們在逛購物網站的時候,我們可以在不同的産品頁面,看到自己喜歡的商品後加入到購物車當中,此時購物車不會是多個重複的執行個體,隻會生成一個執行個體;

3、釋出-訂閱模式

什麼是釋出-訂閱模式?它定義了對象間的一種一對多的關系,讓多個訂閱者對象同時監聽某一個主題對象,當一個對象發生改變時,所有依賴于它的對象都将得到通知。

生活中的案例:我想要買房子,我去我看中的樓盤的售樓處去詢問,但是樓盤還沒有開盤,銷售人員讓我關注他們樓盤的一個公衆号,當樓盤開盤以後,這個公衆号會釋出一個通知,我們接收到這個通知以後,就可以去買房了。

這裡我就是訂閱者,銷售就是釋出者,當樓盤開盤的時候,銷售人員在公衆号上釋出了一條消息,我接受到了這個消息,我就可以過去買房。有很多人和我一樣都想要買這個樓盤的房子,都關注了這個公衆号,但是每個人接收到樓盤開盤的消息以後具體做什麼,有的人去買房了,有的人不想買了,銷售人員管不了,他隻管在公衆号上釋出消息;

什麼時候使用釋出-訂閱模式:

a、各子產品互相獨立

b、存在一對多的依賴關系

c、依賴子產品不穩定、依賴關系不穩定

d、各子產品由不同的人員、團隊開發

釋出-訂閱模式的優點

a、釋出-訂閱模式廣泛應用于異步程式設計之中,是一種替代回調函數的方案.多個事件處理函數可以訂閱同一個事件,當該事件發生後,與其相對應的多個事件處理函數都會運作。

b、一個對象不用再顯示的調用另外一個對象的某個接口,降低子產品之間的耦合程度,雖然不清楚彼此的細節,但是不影響他們之間互相通信

1、dom事件

對一個dom節點的事件進行監聽,當操作dom節點時,觸發相應的事件,相應的函數執     行。事件函數對dom節點完全未知,不用去理會是什麼事件,如何觸發,執行就好。
    document.body.addEventListener(“click”,function() {…})
   2、自定義事件
    假如小明想去看周傑倫的演唱會,但是周傑倫演唱會的門票太火爆,一開始買票瞬間就被搶光了。但是有些人可能隻是搶到票了,最終沒有去付款,這樣的話在一定時間沒有付款的話,訂單失效,票就會釋放出來供大家去搶。是以我在搶票的網站訂閱了演唱會餘票提醒,隻要一有餘票,就會通知小明去搶。           

4、裝飾器模式

什麼是裝飾器模式?是為了給一個函數賦能,增強它的某種能力,它能動态的添加對象的行為,對現有的類對象進行包裹和封裝,以期望在不改變類對象及其類定義的情況下,為對象添加額外功能。

什麼是裝飾器模式:是為了給一個函數賦能,增強它的某種能力,它能動态的添加對象的行為,對現有的類對象進行包裹和封裝,以期望在不改變類對象及其類定義的情況下,為對象添加額外功能。

react當中的高階函數就是裝飾器模式的一個最常見的應用;

5、擴充卡模式

什麼是擴充卡模式?擴充卡用來解決兩個已有接口之間不比對的問題,它并不需要考慮接口是如何實作,也不用考慮将來該如何修改;擴充卡不需要修改已有接口,就可以使他們協同工作;

擴充卡模式的優點:
   a、已有的功能如果隻是接口不相容,使用擴充卡适配已有功能,可以使原有邏輯得到更好的複用,有助于避免大規模改寫現有代碼;
   b、可擴充性良好,在實作擴充卡功能的時候,可以調用自己開發的功能,進而友善地擴充系統的功能;
   c、靈活性好,因為擴充卡并沒有對原有對象的功能有所影響,如果不想使用擴充卡了,那麼直接删掉即可,不會對使用原有對象的代碼有影響;
   1、地圖元件
  2、我們都知道很多UI元件或者工具庫會按指定的資料格式進行渲染,但是這個時候    後端是不知道的;   是以可能接口出來的資料我們是不能直接正常的在頁面上渲染的,    而此時老闆催促我們趕緊上線,而後端堅持認為資料格式沒問題,堅決不修改;這個時候我們可以通過擴充卡模式來前端格式化資料;           

四、總結和感想

設計模式并不是單一的某種方法也沒有固定的适用場景。很多時候可能我們自己在寫代碼的時候可能已經在使用某種設計模式的思想但是我們自己卻不知道。我覺得學習設計模式隻是單純的去看相關的書籍和部落格并不能夠深入的去了解,我覺得在學習的過程中結合自己的項目經驗能夠感悟到其中的精髓才能夠掌握這個思想。設計的再厲害,性能很差,也是一個很差的設計。是以最适合的就是最好的。我希望大家都能夠在實際的工作過程中不斷的去思考和總結怎樣寫出更好的代碼,在前端的道路上能夠走的更遠。

繼續閱讀