關於修改複雜數據結構的思考

注意

本文須要要求讀者由 typescript 和 react 的相關知識才能理解!前端

若是在業務中遇到代碼難梳理,邏輯錯綜複雜,維護性不高的狀況,能夠繼續讀一讀,瞧一瞧react

TL;DR

在我業務中遇到過對複雜結構的數據修改,例如如今有一個數據結構以下(這些都是真實地業務中脫敏出來的)typescript

關於複雜數據的結構描述

interface complexData {
  complexDataUniqueId: string; // 複雜數據結構的 惟一id
  relatedDatas: OtherComplexData[];

  ...otherUnconsideredInfos; // 其餘和本文無關的數據
}

interface OtherComplexData {
  otherComplexDataUniqueId: string; // 複雜數據結構2的 惟一id
  user_info: userInfo;

  ...otherUnconsideredInfos; // 其餘和本文無關的數據
}

interface userInfo {
  user_id: string;
  user_name: string;
  age: number;
  user_follow_info: userFollowInfo;

  ...otherUnconsideredInfos; // 其餘和本文無關的數據
}

interface userFollowInfo {
  relation_type: RelationType;

  ...otherUnconsideredInfos; // 其餘和本文無關的數據
}

enum RelationType {
  // 互不關注
  NON_FOLLOW = 0,
  // 已關注
  FOLLOWED = 1,
  // 被關注
  FOLLOWING = 2,
  // 互相關注
  MUTUAL_FOLLOWING = 3
}
複製代碼

正文

如上所示數據結構至關之複雜,一個複雜的數據結構中包含了另一個複雜的數據結構,另一種複雜的數據結構中包含了用戶的信息,用戶的信息中包含了該用戶和當前登陸用戶的關係數組

而後在如今業務上需求是,由一個 complexData[] 的數組,輸入一個 otherComplexDataUniqueId 匹配到其對應的關聯的數據,而後修改這個結構的用戶關係(好比 從 互不關注 變成 已關注)微信

按照面向過程的思考方式,咱們能夠很快的寫出一段僞代碼markdown

state = {
  complexDatas: [complexData, complexData, complexData, ...]
}

followSomeUser (targetId: string) {
  // 也許就在你的業務代碼中也會像我同樣,充斥着大量大段大段的相似這樣的函數
  // 邏輯錯綜複雜,功能難以維護
  this.setState({
      complexDatas: complexDatas.map(item => {
      item.relatedDatas.map(cItem => {
        if (targetId === cItem.otherComplexDataUniqueId) {
          cItem = {
            ...cItem,
            cItem.user_info = {
              ...cItem.user_info,
              user_follow_info: {
                ...cItem.user_info.user_follow_info,
                relation_type: RelationType.FOLLOWED // 修改爲已經關注
              }
            }
          }
        }
      })
    })
  })
}
複製代碼

思路很清晰,保持全部其餘的數據不變,並返回新的引用(react) 可是這樣寫實在是很是的複雜醜陋,讓人摸不清邏輯,做者可能沒幾個月後也會忘記數據結構

因此,咱們在寫業務代碼中,須要能夠很好的把代碼邏輯拆分,下面讓咱們來簡單把上述的僞代碼作一個拆分和解構ide

咱們把代碼分紅兩個部分,查找 和 賦值函數

首先是查找,咱們能夠把查找抽象成一個函數來作ui

// 函數式的查找須要修改的目標, 匹配目標id
const match = (o: otherComplexData, targetId: string) =>  o.otherComplexDataUniqueId === targetId;
複製代碼
// 賦值(對於數據結構的更新,和更新補丁相似,因此叫patch)
const patchOtherComplexDataFollowRelation = (o: otherComplexData, relation_type: RelationType) => {
  return  {
    ...o,
    o.user_info = {
      ...o.user_info,
      user_follow_info: {
        ...o.user_info.user_follow_info,
        relation_type // 修改爲已經關注
      }
    }
  }
}
複製代碼

而後是遍歷並修改

const updateList = (list: complexData[], targetId: string) => {
  return list.map(item => item.relatedDatas.map(cItem => { match(cItem, targetId) ? ...patchOtherComplexDataFollowRelation(cItem, RelationType.FOLLOWED) : cItem} ))
}
複製代碼

讓咱們完整地看看用函數式 + 解耦的方式寫

state = {
  complexDatas: [complexData, complexData, complexData, ...]
}

followSomeUser (targetId: string) {
  const match = (o: otherComplexData, targetId: string) =>  o.otherComplexDataUniqueId === targetId;

  const patchOtherComplexDataFollowRelation = (o: otherComplexData, relation_type: RelationType) => {
    return  {
      ...o,
      o.user_info = {
        ...o.user_info,
        user_follow_info: {
          ...o.user_info.user_follow_info,
          relation_type // 修改爲已經關注
        }
      }
    }
  }

  const updateList = (list: complexData[], targetId: string) => {
    return list.map(item => item.relatedDatas.map(cItem => { match(cItem, targetId) ? ...patchOtherComplexDataFollowRelation(cItem, RelationType.FOLLOWED) : cItem} ))
  }

  // 這樣看起來是否是很是的清晰,讓人易於理解?
  this.setState(s => ({ complexDatas: updateList(s.complexDatas) }))
}
複製代碼

經過兩種方式的比較,咱們能夠明確認識到,當咱們平時業務中遇到一大段很是複雜的邏輯的時候,必定要學會梳理脈絡 把複雜的邏輯多解耦,該拆分拆分,這樣才能讓咱們寫的代碼更具有更好的可讀性和可維護性

廣告

字節跳動IES招前端啦,有興趣有能力的同窗能夠加我微信:L_star07 私聊~

工做地點基本涵蓋全國各大一線城市,歡迎您的到來呀

相關文章
相關標籤/搜索