<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一個(gè)Go方法,五種變換

          共 4781字,需瀏覽 10分鐘

           ·

          2021-11-19 09:43

          今天帶大家來一段代碼的變換之旅,代碼篇幅較多,主要參考自one-way-to-do-it-six-variations,土撥鼠在這里加了一些自己的理解。

          文章: https://phlatphrog.medium.com/one-way-to-do-it-six-variations-cd58602ac06d

          代碼倉庫: https://github.com/pdk/oneway

          我們先來模擬一段開車去商場購物的代碼。主要經(jīng)歷三個(gè)階段:開車去商店、到商店購物、然后購物完成開車回家。每個(gè)過程都需要去check其中返回的err錯(cuò)誤并返回shopper對象。

          //?開車去商店?
          shopper,?err?:=?shopper.Drive(FuelNeededToGetToStore)
          if?nil?!=?err?{
          ????log.Fatalf("could?not?complete?shopping:?%s",?err)
          }
          //?買雞蛋?
          shopper,?err?=?shopper.BuyEggs(EggsRequired)
          if?nil?!=?err?{
          ????log.Fatalf("could?not?complete?shopping:?%s",?err)
          }
          //?買完雞蛋開車回家?
          shopper,?err?=?shopper.Drive(FuelNeededToGetHome)
          if?nil?!=?err?{
          ????log.Fatalf("could?not?complete?shopping:?%s",?err)
          }

          變換1:err集中判斷

          針對這段代碼,錯(cuò)誤處理代碼較多,可以將三個(gè)重復(fù)代碼塊抽離成一個(gè)代碼塊。代碼如下:

          func?main(){
          ????shopper,?err?:=?shopper.Drive(FuelNeededToGetToStore)
          ????FatalIfErrNotNil(err)
          ????shopper,?err?=?shopper.BuyEggs(EggsRequired)
          ????FatalIfErrNotNil(err)
          ????shopper,?err?=?shopper.Drive(FuelNeededToGetHome)
          ????FatalIfErrNotNil(err)
          }??

          func?FatalIfErrNotNil(err?error)?{
          ????if?nil?!=?err?{
          ????????log.Fatalf("could?not?complete?shopping:?%s",?err)
          ????}
          }

          不過在生產(chǎn)項(xiàng)目中,正常業(yè)務(wù)我們一般不會(huì)使用fatal去對非nilerr處理,fatal會(huì)以非0狀態(tài)退出程序。而是使用https://github.com/pkg/errors對err進(jìn)行wrapcause 或者使用定義的業(yè)務(wù)相關(guān)的err并返回上一層做處理。這里也可以嘗試使用bool判斷來對err處理(不過之前土撥鼠之前群里也提出這樣的想法,大家都說多此一舉,尷尬)。

          func?main(){
          ????shopper,?err?:=?shopper.Drive(FuelNeededToGetToStore)
          ????if?ErrorHandled(err)?{
          ??????return?...
          ????}
          }

          func?ErrorHandled(err)?bool?{
          ??if?nil?!=?err?{
          ????return?true
          ??}
          ??//?也可以對error進(jìn)行其他判斷操作
          ??...
          ??return?false
          }

          變換2:方法中包括err處理

          是不是覺得上面的err處理還是不夠優(yōu)雅,所以咱們這里考慮把err的處理移出到主線之外。每個(gè)方法里都包含了對err的非nil判斷和返回。每個(gè)操作也只有在errnil的情況下正常執(zhí)行 。只有在三個(gè)操作都結(jié)束后才真正對err進(jìn)行處理。

          func?main(){
          ??shopper,?err?:=?shopper.Drive(FuelNeededToGetToStore,?nil)
          ????shopper,?err?=?shopper.BuyEggs(EggsRequired,?err)
          ????shopper,?err?=?shopper.Drive(FuelNeededToGetHome,?err)
          ????if?nil?!=?err?{
          ????????log.Fatalf("could?not?complete?shopping:?%s",?err)
          ????}
          }

          func?(s?Shopper)?Drive(fuelRequired?int,?err?error)?(Shopper,?error)?{
          ????if?nil?!=?err?{
          ????????return?s,?err
          ????}
          ???//?業(yè)務(wù)邏輯處理
          ????...?
          }

          變換3:使用函數(shù)對err分解

          下面這個(gè)變換,拋棄了之前Shopper作為receiver的做法,而是將Shopper作為函數(shù)的參數(shù)。其實(shí)跟變換2很相似。這兒是單獨(dú)抽離出一個(gè)公共的函數(shù)ErrCheckFunc進(jìn)行err處理和函數(shù)執(zhí)行。

          func?main(){
          ????drive?:=?ErrCheckFunc(Drive)
          ????buy?:=?ErrCheckFunc(BuyEggs)
          ????err,?shopper?:=?drive(nil,?shopper,?FuelNeededToGetToStore)
          ????err,?shopper?=?buy(err,?shopper,?EggsRequired)
          ????err,?shopper?=?drive(err,?shopper,?FuelNeededToGetHome)
          ????if?nil?!=?err?{
          ????????log.Fatalf("could?not?complete?shopping:?%s",?err)
          ????}
          }

          func?Drive(s?Shopper,?fuelRequired?int)?(Shopper,?error)?{
          ????if?nil?!=?err?{
          ????????return?s,?err
          ????}
          ???...
          }

          func?ErrCheckFunc(f?func(Shopper,?int)?(Shopper,?error))?func(error,?Shopper,?int)?(error,?Shopper)?{
          ????return?func(err?error,?s?Shopper,?arg?int)?(error,?Shopper)?{
          ????????if?nil?!=?err?{
          ????????????return?err,?s
          ????????}
          ????????s,?err?=?f(s,?arg)
          ????????return?err,?s
          ????}
          }

          變換4:單行操作

          這次改進(jìn)是采用了裝飾器模式的思想把errcheck邏輯和函數(shù)的執(zhí)行操作都封裝在了ErrCheckFunc一個(gè)方法中。相比變換3,是將ErrCheckFunc中的返回值中的函數(shù)入?yún)?code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(60, 112, 198);">arg轉(zhuǎn)移到了ErrCheckFunc入?yún)⒅械?code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(60, 112, 198);">arg參數(shù)。

          func?main(){
          ????driveToStore?:=?ErrCheckFunc(Drive,?FuelNeededToGetToStore)
          ????buyEggs?:=?ErrCheckFunc(BuyEggs,?EggsRequired)
          ????driveHome?:=?ErrCheckFunc(Drive,?FuelNeededToGetHome)
          ??
          ????err,?shopper?:=?driveHome(buyEggs(driveToStore(nil,?shopper)))
          ????if?nil?!=?err?{
          ????????log.Fatalf("could?not?complete?shopping:?%s",?err)
          ????}
          }

          func?ErrCheckFunc(f?func(Shopper,?int)?(Shopper,?error),?arg?int)?func(error,?Shopper)?(error,?Shopper)?{
          ????return?func(err?error,?s?Shopper)?(error,?Shopper)?{
          ????????if?nil?!=?err?{
          ????????????return?err,?s
          ????????}
          ????????s,?err?=?f(s,?arg)
          ????????return?err,?s
          ????}
          }

          變換5:迭代變換

          終極變換來了,這次變換采用了迭代的思想。ProcessSteps這里使用的是一個(gè)可變的函數(shù)參數(shù)。

          func?main(){
          ????driveToStore?:=?Flavorize(Drive,?FuelNeededToGetToStore)
          ????buyEggs?:=?Flavorize(BuyEggs,?EggsRequired)
          ????driveHome?:=?Flavorize(Drive,?FuelNeededToGetHome)
          ??
          ????shopper,?err?:=?ProcessSteps(shopper,
          ????????driveToStore,
          ????????buyEggs,
          ????????driveHome,
          ????)
          ????if?nil?!=?err?{
          ????????log.Fatalf("could?not?complete?shopping:?%s",?err)
          ????}
          }

          func?ProcessSteps(s?Shopper,?steps?...func(Shopper)?(Shopper,?error))?(Shopper,?error)?{
          ????for?_,?step?:=?range?steps?{
          ????????var?err?error?
          ????????s,?err?=?step(s)
          ????????if?nil?!=?err?{
          ????????????return?s,?err
          ????????}
          ????}
          ????return?s,?nil
          }

          func?Flavorize(f?func(Shopper,?int)?(Shopper,?error),?arg?int)?func(Shopper)?(Shopper,?error)?{
          ?return?func(s?Shopper)?(Shopper,?error)?{
          ??return?f(s,?arg)
          ?}
          }

          小結(jié)

          土撥鼠今天拿這個(gè)例子來展示給大家,主要是因?yàn)樵陧?xiàng)目中也會(huì)經(jīng)常遇到這樣的代碼邏輯場景,就想著看看別人是怎么去重構(gòu)改進(jìn)的,學(xué)習(xí)怎么去優(yōu)化重構(gòu),使代碼變得更好維護(hù)、易于擴(kuò)展、復(fù)用性高、可讀性高。希望大家也可以借鑒學(xué)習(xí),如果你有更好的變換和想法歡迎大家留言討論。



          推薦閱讀


          福利

          我為大家整理了一份從入門到進(jìn)階的Go學(xué)習(xí)資料禮包,包含學(xué)習(xí)建議:入門看什么,進(jìn)階看什么。關(guān)注公眾號 「polarisxu」,回復(fù)?ebook?獲取;還可以回復(fù)「進(jìn)群」,和數(shù)萬 Gopher 交流學(xué)習(xí)。

          瀏覽 24
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黑人下面太大我高潮了 | 天天爽天天爽天天爽天天爽天天爽 | 青青青操操 | 黄色日本免费看 | 国产日韩无码视频 |