項目實戰(zhàn) 業(yè)務(wù)處理層實現(xiàn)

前言

前文傳送地址:

設(shè)計模式-基礎(chǔ)請求封裝

前端設(shè)計模式之工廠模式

前端設(shè)計模式之代理模式

前端設(shè)計模式之策略模式

連續(xù)四篇設(shè)計模式都是前端經(jīng)常使用到的,相信大家參考博文中的項目實戰(zhàn)之后再去琢磨自己的項目代碼、或者看一些優(yōu)秀的開源代碼對比后,能更深刻的體會到設(shè)計模式(Design pattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過分類編目的、代碼設(shè)計經(jīng)驗的總結(jié)這句話的含義。

(小聲BB,某人的埋點博客終于快到尾聲了)

在開發(fā)的過程中,同一種功能采用不同的或者組合的設(shè)計模式實現(xiàn),可以將代碼質(zhì)量提升。這里要 copy 第一篇博文的話重申一下為什么前端需要了解設(shè)計模式

在日常開發(fā)中大部分前端都在開發(fā)的中,進行組件、方法等封裝、提煉的時候或多或少已經(jīng)使用了一些設(shè)計模式的理念, 但是由于對設(shè)計模式的概念模糊,理解不夠,從而導(dǎo)致設(shè)計整體架構(gòu)的時候,會有各種局限性,拓展性、可讀性、維護性變差,不得不多次重構(gòu)甚至重寫。在 ts 在前端開發(fā)中加速推進的同時,合理的設(shè)計模式使得項目從架構(gòu)、設(shè)計、迭代、維護都有一定質(zhì)量的保障。

接下來我們通過使用設(shè)計模式中的工廠、代理模式來繼續(xù)改造我們的 fetch 工程

封裝 fetch 業(yè)務(wù)部分

業(yè)務(wù)層普通封裝

業(yè)務(wù)層的封裝,我們在上一篇的文末已經(jīng)提到過,這邊再結(jié)合代碼展示一下

一般來說我們的工程會有多個模塊,這邊我們先根據(jù)各個模塊封裝一層 service 層,方便我們業(yè)務(wù)側(cè)調(diào)用。

import Fetch from './util/fetch';

const prefix = 'https://api.github.com/users'

const fetch = new Fetch({ requestType: "JSON", cacheType: 'local', BASE_URL: prefix });

const getUser = (params) => {
  return new Promise((resolve, reject) => {
    fetch.get({
      url: '/octocat',
      params
    }).then(response => {
      const { data, code, errMessage } = response
      if (code) {
        resolve(data)
      } else {
        reject(errMessage)
      }
    })
  })
}

const setUser = (params) => {
  return new Promise((resolve, reject) => {
    fetch.post({
      url: '/octocat',
      params
    }).then(response => {
      const { data, code, errMessage } = response
      if (code) {
        resolve(data)
      } else {
        reject(errMessage)
      }
    })
  })
}

export {
  getUser,
  setUser
};
export default {
  getUser,
  setUser
}

如上我們封裝了一個用戶 service 層,一般來說,除了正常的 http 的請求狀態(tài)異常之外,會有業(yè)務(wù)處理的異常。所以在 service 層調(diào)用的時候,可以預(yù)先處理掉錯誤的異常,返回給業(yè)務(wù)側(cè)正常的數(shù)據(jù),業(yè)務(wù)側(cè)在調(diào)用的時候,可以直接使用 try/catch 去承接數(shù)據(jù)。同時在多個業(yè)務(wù)側(cè)都需要調(diào)用相同的接口的時候,可以在用戶 service 層處理、過濾一些后臺返回的參數(shù),這樣可以使得業(yè)務(wù)側(cè)調(diào)用到方便前端展示的數(shù)據(jù)(比如組裝列表數(shù)據(jù),日期、金額格式化等)。

但是當業(yè)務(wù)過多,都要處理統(tǒng)一的業(yè)務(wù)錯誤的時候,會顯得非常麻煩,造成冗余代碼跟維護困難,所以在這之上,我們可以在針對 service 層再做一層業(yè)務(wù)報錯封裝。

import Fetch from '../util/fetch';

const prefix = 'https://api.github.com'

const fetch = new Fetch({ requestType: "JSON", cacheType: 'local', BASE_URL: prefix });

const get = (url, params) => {
  return new Promise((resolve, reject) => {
    fetch.get({
      url,
      params
    }).then(response => {
      const { data, code, errMessage } = response
      if (code) {
        resolve(data)
      } else {
        reject(errMessage)
      }
    })
  })
}

export {
  get
};

export default {
  get
}

如上可以將業(yè)務(wù)層的統(tǒng)一處理跟單獨的業(yè)務(wù)接口數(shù)據(jù)處理分開,用戶的 service 層改造如下

import { get, post } from './baseFetch';

const prefix = 'users'

const getUser = async (params) => {
  try {
    const data = get({
      url: `${prefix}/octocat`,
      params
    })
    return data
  }
}

const setUser = (params) => {
  try {
    const data = post({
      url: `${prefix}/octocat`,
      params
    })
    return data
  }
}

export {
  getUser,
  setUser
};

export default {
  getUser,
  setUser
}

業(yè)務(wù)層 restful 格式封裝

有些后臺接口是按照 restful 風格封裝的接口,如果還是按照上面的封裝,會顯得比較累贅,我們可以如下封裝一下

import baseFetch from './baseFetch';

const prefix = 'users'

const methods = ['get', 'post', 'put', 'delete']

const userUrl = {
  users: 'octocats',
  user: 'octocat'
}

const user = {}
Object.keys(userUrl).forEach(key => {
  user[key] = {}
  methods.forEach(method => {
    user[key][method] = (params) => {
      return baseFetch[method](`${prefix}/${userUrl[key]}`, params)
    }
  })
})

export {
  user
};

export default {
  user
}

user.user.get({ test: 1 }) // 業(yè)務(wù)側(cè)調(diào)用
user.user.post({ test: 1 }) // 業(yè)務(wù)側(cè)調(diào)用

如上我們將 url 跟請求方法組裝起來,業(yè)務(wù)側(cè)調(diào)用會簡便很多,但是中間的業(yè)務(wù)層數(shù)據(jù)處理似乎就沒了,我們可以將 userUrl 拓展成 userObj,把數(shù)據(jù)處理方法也放入對象里面,改造如下

const userObj = {
  users: {
    url: 'octocats',
    get(data) { return data }
  },
  user: {
    url: 'octocats',
    post(data) { return data }
  }
}

const user = {}
Object.keys(userObj).forEach(key => {
  user[key] = {}
  methods.forEach(method => {
    user[key][method] = (params) => {
      return new Promise((resolve) => {
        baseFetch[method](`${prefix}/${userObj[key].url}`, params).then(data => {
          if (userObj[key][method]) resolve(userObj[key][method](data))
          resolve(data)
        })
      })
    }
  })
})

尾聲

完整的 demo 地址:項目實戰(zhàn) demo,喜歡的朋友可以 star 一下,后續(xù)會根據(jù)設(shè)計模式博文的推出,逐步的將此項目繼續(xù)拓展出來。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容