手摸手教你在前端開發中使用設計模式

前言

提到設計模式可能你們會感受有點高大上的感受,其實這個東西的概念很抽象,可是在實際開發中仍是有不少地方可使用設計模式的思想,對咱們的代碼進行一次優化。本文旨在介紹一些開發中經常使用的設計模式,經過例子來進行學習,儘可能對概念一帶而過。爲了討隔壁前端小姐姐的崇拜的目光,一塊兒學一下吧!前端

image.png

正文

1. 適配器模式

概念:將一個類的接口轉化成另一個接口,以知足用戶需求,使類(對象)之間的接口的不兼容問題經過適配器得以解決。vue

在工做中,有時爲了知足需求,在開發新模塊的時候須要對老模塊作一個兼容,這時候就須要適配器模式。ios

例如ajax

  1. 方法默認傳參
// 參數大於2建議使用對象進行合併
function doSomeThing(obj){
  const adapter = {
    name:"默認姓名",
    color:"red",
    size:200,
    age:20
  }
  for (let i in adapter){
    adapter[i] = obj[i] || adapter[i];
  }
  // do some thing
}
複製代碼

能夠看到這麼處理以後咱們不管傳入的參數是什麼均可以保證對象中擁有這幾個屬性。避免後續邏輯出錯。算法

  1. 全局封裝方法的擴展與兼容。

在vue使用中,咱們一般會將api請求掛載在vue實例上,可是有些老的項目是經過封裝ajax請求,在對老項目進行重構時須要將全部的api請求放到axios上或者fetch上。這就可使用適配器模式。axios

// 對fetch 封裝僞代碼
export default class FetchApi{
    static get(url){
		return new Promise((resolve,reject)=>{
      fetch(url).then(...).catch(err=>reject(err))
    })
	}
  static post(url,data){
    return new Promise(...)
  }
}
  
// 在使用時咱們能夠這麼使用
  const res = await FetchApi.get(url) || {};
// 或者
  const res = await FetchApi.post(url,params) || {}
  
  
// 再看一下原有的接口封裝方式  僞代碼
  function Ajax(type,url,data){
    const xhr = new XMLHttpRequest()
    ...
    if(type === 'GET'){
      xhr.open('GET',url+"?"+data,true);
      xhr.send()
    }else if(type === 'POST'){
        xhr.open('POST',url,true);
        xhr.setRequestHeader("Content-type",'application/x-www-form-urlencoded')
    	xhr.send(data)
    }
    ...
  }
  
  // 調用方式
  Ajax("GET",url,data)
  
複製代碼

在這裏咱們能夠看到新老接口的接口名不同,請求傳參也不同。不要緊,使用適配器解決。設計模式

// 僞代碼  
  async function ajaxAdapterr(type,url,data){
    let result
    if(type === 'GET'){
      result = await FetchApi.get(url) || {}
    }else if(type === 'POST'){
      result = await FetchApi.post(url,data) || {}
    }
  }
    
   async function Ajax(type,url,data){
        await ajaxAdapterr(type,url,data);
   }
複製代碼

這樣就能夠對原有的ajax請求變動到fetch上,避免一個個去修改頁面中的請求。節省大量了時間能夠用來摸魚。api

image.png

2. 策略模式

概念:將定義的一組算法封裝起來,使其相互之間能夠替換。封裝的算法具備必定的獨立性,不會隨客戶端的變化而變化。緩存

概念這東西就是善於將人人都懂的東西描述成人人都不懂。咱們仍是看實際場景吧。markdown

工做中,相信你們必定寫過不少不少的if else判斷。當條件愈來愈多的時候,這種書寫方式就會變得特別臃腫,那麼就用策略模式優化一下吧。

例如

function doSomeThing(type){
  if(type === 'pre'){
    return 100
  }else if(type === 'onSale'){
    return 200
  }else if(type === 'back'){
    return 150
  }else if(type === 'fresh'){
    return 250
  }
}

// 邏輯會愈來愈臃腫 用策略模式優化一下
function doSomeThing(type){
  const priceType = {
    pre(){
      return 100
    },
    onSale(){
      return 200
    },
    back(){
      return 150
    },
    fresh(){
      return 250
    }
  }
  return priceType[type]()
}
複製代碼

能夠看到,在使用策略模式優化以後,代碼的映射關係很明確,而且更加的靈活直觀,後期的維護只須要去在對象中添加方法便可。帥就一個字,我只說一次。這樣的代碼哪一個前端小姐姐看了不說棒呢?

3. 狀態模式

概念:當一個對象的內部狀態發生改變時,會致使其行爲的改變,這看起來像是改變了對象。

狀態模式的概念與策略模式相似,都是封裝行爲、都經過委託來實現行爲分發。可是策略模式裏面分發的方法,沒有依賴,互相平行,進水不犯河水。而狀態模式裏,各函數與主體存在必定的關聯。

例如

自動咖啡機

class Coffee{
  constructor(){
    this.state ='黑咖啡';
  }
  stateProcessor = {
      american: () => {
         console.log("黑咖啡")
      },
      latte: () => {
          this.stateProcessor.american(); // 製做黑咖啡
          console.log("加奶")
      },
      vanillaLatte: () => {
           this.stateProcessor.latte();
           console.log("加香草🌿糖漿")
      },
      mocha: () => {
            this.stateProcessor.latte();
            console.log('加巧克力🍫')
      }
  }
 
  changeState(state){
    this.state = state;
    if(!this.stateProcessor[state]){
      return console.log("暫無此咖啡")
    }
    this.stateProcessor[state]()
  }
}

const coffee = new Coffee();
coffee.changeState("latte")
複製代碼

狀態模式主要解決的是當控制一個對象狀態的條件表達式過於複雜時的狀況,把狀態的判斷邏輯轉移到表示不一樣狀態的一系列類中,能夠把複雜的判斷邏輯簡化。

4. 代理模式

概念:因爲一個對象不能直接引用另外一個對象,因此須要經過代理對象在這兩個對象之間起到中介做用。

代理你們可能日常開發中都有涉及到,基本那種代理這裏不作介紹,這裏介紹一下緩存代理

例如: 對入參進行求和處理

// addAll方法會對你傳入的全部參數作求和操做
const addAll = function() {
    console.log('進行了一次新計算')
    let result = 0
    const len = arguments.length
    for(let i = 0; i < len; i++) {
        result += arguments[i]
    }
    return result
}

// 爲求和方法建立代理
const proxyAddAll = (function(){
    // 求和結果的緩存池
    const resultCache = {}
    return function() {
        // 將入參轉化爲一個惟一的入參字符串
        const args = Array.prototype.join.call(arguments, ',')
        // 檢查本次入參是否有對應的計算結果
        if(args in resultCache) {
            // 若是有,則返回緩存池裏現成的結果
            return resultCache[args]
        }
        return resultCache[args] = addAll(...arguments)
    }
})()
複製代碼

image-20210719122848035.png

能夠看到,在入參一致的狀況下,只作了一次計算,後續都是從緩存中取值進行返回,這在計算量特別大的狀況下將會極大節省時間開銷。

5. 裝飾者模式

概念: 在不改變原對象的基礎上,經過對其進行包裝擴展(添加屬性或者方法),使得原有對象能夠知足更復雜的需求。

例如: 在審批流中,原需求是審批經過拒絕都放在了一塊兒進行了處理,後期增長了需求,在拒絕時須要顯示一個彈框輸入拒絕緣由

// 原有的審批邏輯
function approvalOrReject(){
	// do some thing
}

function rejectShowBox(){
	this.approvalOrReject();
	this.showMessageBox(); // 顯示彈框
}
複製代碼

如此一來,咱們就實現了「只添加,不修改」的裝飾器模式。實際開發中的裝飾器模式用處特別多,你們能夠用心去發現~

小結

暫時先總結這些設計模式吧,後續還會繼續整理添加,請你們點贊收藏關注咯~

自從用了設計模式,小姐姐都開始對我頻頻點頭了,兄弟們,用起來吧。

因爲本人水平有限,文內若有錯誤歡迎與我聯繫。

相關文章
相關標籤/搜索