美文网首页
项目实战 业务处理层实现

项目实战 业务处理层实现

作者: Cookieboty | 来源:发表于2020-11-11 14:17 被阅读0次

    前言

    前文传送地址:

    设计模式-基础请求封装

    前端设计模式之工厂模式

    前端设计模式之代理模式

    前端设计模式之策略模式

    连续四篇设计模式都是前端经常使用到的,相信大家参考博文中的项目实战之后再去琢磨自己的项目代码、或者看一些优秀的开源代码对比后,能更深刻的体会到设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结这句话的含义。

    (小声BB,某人的埋点博客终于快到尾声了)

    在开发的过程中,同一种功能采用不同的或者组合的设计模式实现,可以将代码质量提升。这里要 copy 第一篇博文的话重申一下为什么前端需要了解设计模式

    在日常开发中大部分前端都在开发的中,进行组件、方法等封装、提炼的时候或多或少已经使用了一些设计模式的理念, 但是由于对设计模式的概念模糊,理解不够,从而导致设计整体架构的时候,会有各种局限性,拓展性、可读性、维护性变差,不得不多次重构甚至重写。在 ts 在前端开发中加速推进的同时,合理的设计模式使得项目从架构、设计、迭代、维护都有一定质量的保障。

    接下来我们通过使用设计模式中的工厂、代理模式来继续改造我们的 fetch 工程

    封装 fetch 业务部分

    业务层普通封装

    业务层的封装,我们在上一篇的文末已经提到过,这边再结合代码展示一下

    一般来说我们的工程会有多个模块,这边我们先根据各个模块封装一层 service 层,方便我们业务侧调用。

    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 的请求状态异常之外,会有业务处理的异常。所以在 service 层调用的时候,可以预先处理掉错误的异常,返回给业务侧正常的数据,业务侧在调用的时候,可以直接使用 try/catch 去承接数据。同时在多个业务侧都需要调用相同的接口的时候,可以在用户 service 层处理、过滤一些后台返回的参数,这样可以使得业务侧调用到方便前端展示的数据(比如组装列表数据,日期、金额格式化等)。

    但是当业务过多,都要处理统一的业务错误的时候,会显得非常麻烦,造成冗余代码跟维护困难,所以在这之上,我们可以在针对 service 层再做一层业务报错封装。

    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
    }
    

    如上可以将业务层的统一处理跟单独的业务接口数据处理分开,用户的 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
    }
    

    业务层 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 }) // 业务侧调用
    user.user.post({ test: 1 }) // 业务侧调用
    

    如上我们将 url 跟请求方法组装起来,业务侧调用会简便很多,但是中间的业务层数据处理似乎就没了,我们可以将 userUrl 拓展成 userObj,把数据处理方法也放入对象里面,改造如下

    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 地址:项目实战 demo,喜欢的朋友可以 star 一下,后续会根据设计模式博文的推出,逐步的将此项目继续拓展出来。

    相关文章

      网友评论

          本文标题:项目实战 业务处理层实现

          本文链接:https://www.haomeiwen.com/subject/xdvebktx.html