偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Go 工程化之如何優(yōu)雅的寫出 Repo 層代碼

開發(fā) 前端
我們?cè)讷@取文章的時(shí)候大部分時(shí)候可能都是通過(guò) id 獲取的,但是我們也可能通過(guò)標(biāo)題等其它信息獲取文章的數(shù)據(jù),這時(shí)候我們的 repo 層代碼怎么寫呢?

[[442185]]

上篇文章中我們提到了事務(wù)的幾種解決方案,可以避免在 repo 中寫很多不同事務(wù)的方法,這篇我們看一下怎么讓 repo 層的代碼看起來(lái)優(yōu)雅一點(diǎn)

還是以獲取一篇文章為例,我們?cè)讷@取文章的時(shí)候大部分時(shí)候可能都是通過(guò) id 獲取的,但是我們也可能通過(guò)標(biāo)題等其它信息獲取文章的數(shù)據(jù),這時(shí)候我們的 repo 層代碼怎么寫呢?

最簡(jiǎn)單的方式,就是我們直接在 repo 這里寫兩個(gè)方法

  1. // IArticleRepo IArticleRepo 
  2. type IArticleRepo interface { 
  3.  GetArticleByTitle(ctx context.Context, title string) (*Article, error) 
  4.  GetArticleByID(ctx context.Context, id int) (*Article, error) 

這樣最簡(jiǎn)單也最直觀,但是問(wèn)題是我們的實(shí)際的業(yè)務(wù)需求往往比我們的例子復(fù)雜,如果我們需要通過(guò) id 或者標(biāo)題獲取呢?再添加一個(gè) GetArticleByIDOrTitle ?

這么做的話也不是不行,但是這么做的話就會(huì)讓我們的 repo 的代碼隨著時(shí)間的增長(zhǎng)越來(lái)越多不說(shuō),命名也是問(wèn)題,因?yàn)榻M合的方式可能是多種多樣的

接下來(lái)給大家提供一種我們正在使用的一種思路,利用 Function Options 這種 Go 常見(jiàn)的編程范式,使我們的 repo 更優(yōu)雅,也可擴(kuò)展

DBOption

注意: 筆者這里使用的是 GORM,但是這種方式不僅僅適用于 orm 的情況,只是相對(duì)方便一點(diǎn)而已

  1. type DBOption func(*gorm.DB) *gorm.DB 
  2. // IArticleRepo IArticleRepo 
  3. type IArticleRepo interface { 
  4.  WithByID(id uint) DBOption 
  5.  WithByTitle(title string) DBOption 
  6.  GetArticle(ctx context.Context, opts ...DBOption) (*Article, error) 

我們定義一個(gè)的 DBOption 這個(gè) Option 方法會(huì)作為我們 repo 層方法中的最后一個(gè)參數(shù),這樣我們?cè)诙x方法的時(shí)候就可以簡(jiǎn)潔一些,就不必定義很多 GetArticleByXXX 方法了,而是通過(guò)定義很多 WithByXXX 的 Option 方法來(lái)解決。

這樣在 usecase 層,我們只需要這么調(diào)用即可

  1. func (u *article) GetArticle(ctx context.Context, id int) (*domain.Article, error) { 
  2.  // 這里可能有其他業(yè)務(wù)邏輯... 
  3.  return u.repo.GetArticle(ctx, u.repo.WithByID(uint(id))) 

優(yōu)點(diǎn)

復(fù)用: 雖然看上去我們只是把 GetArticleByXXX 換成了 WithByXXX 該有的方法并沒(méi)有變少,但是我們拆分之后會(huì)發(fā)現(xiàn)很多可以復(fù)用的方法,例如 WithByID 這種幾乎是每個(gè)實(shí)體都會(huì)有的方法,我們就不用重復(fù)寫了。

  1. // GetArticle 和 GetAuthor 都能用上 
  2. func (u *article) GetArticle(ctx context.Context, id int) (*domain.Article, error) { 
  3.  // 這里可能有其他業(yè)務(wù)邏輯... 
  4.  return u.repo.GetArticle(ctx, u.repo.WithByID(uint(id))) 
  5. func (u *article) GetAuthor(ctx context.Context, id int) (*domain.Author, error) { 
  6.  // 這里可能有其他業(yè)務(wù)邏輯... 
  7.  return u.repo.GetAuthor(ctx, u.repo.WithByID(uint(id))) 

最小化: 這么修改了之后,拆分組合更加方便了,很多查詢條件都可以最小化,例如我們可以添加一個(gè) WithSelects 的方法,我們?cè)?usecase 調(diào)用的時(shí)候就可以傳入當(dāng)前場(chǎng)景只需要關(guān)注的字段就可以了

  1. // GetArticle 返回文章的同時(shí)也需要返回作者的名字 
  2. func (u *article) GetArticle(ctx context.Context, id int) (*domain.Article, error) { 
  3.  article, err := u.repo.GetArticle(ctx, u.repo.WithByID(uint(id))) 
  4.  if err != nil { 
  5.   return err 
  6.  } 
  7.  article.Author, err = u.repo.GetAuthor(ctx, u.repo.WithByArticleID(id), u.repo.WithBySelects("id""name")) 
  8.  return article, err 

可測(cè)性: repo 層的測(cè)試會(huì)變得更加方便,這樣修改之后我們可以將查詢條件拆分出來(lái)進(jìn)行測(cè)試,會(huì)比之前耦合在一起測(cè)試簡(jiǎn)單很多。

抽象: 這種方式可以讓我們抽象 CURD 接口更加方便,在 repo 層實(shí)現(xiàn)的時(shí)候,我們可以直接把 curd 的方法都給抽象出來(lái)

  1. // 這里以創(chuàng)建為例 
  2. func (r *userRepo) optionDB(ctx context.Context, opts ...model.DBOption) *gorm.DB { 
  3.  db := r.db.WithContext(ctx) 
  4.  for _, opt := range opts { 
  5.   db = opt(db) 
  6.  } 
  7.  return db 
  8. func (r *userRepo) create(ctx context.Context, data any, opts ...model.DBOption) error { 
  9.  db := r.optionDB(ctx, opts...) 
  10.  err := db.Create(data).Error 
  11.  if err != nil { 
  12.   return pb.ErrorDbCreateFailf("err: %+v", err) 
  13.  } 
  14.  return nil 

總結(jié)

今天給大家介紹了使用 Function Option 的方式來(lái)寫 repo 層的代碼,接下來(lái)我們就簡(jiǎn)單總結(jié)一下

  1. type DBOption func(*gorm.DB) *gorm.DB 
  2. // IArticleRepo IArticleRepo 
  3. type IArticleRepo interface { 
  4.  WithByID(id uint) DBOption 
  5.  WithByTitle(title string) DBOption 
  6.  GetArticle(ctx con 

優(yōu)點(diǎn)

  • 復(fù)用: 雖然看上去我們只是把 GetArticleByXXX 換成了 WithByXXX 該有的方法并沒(méi)有變少,但是我們拆分之后會(huì)發(fā)現(xiàn)很多可以復(fù)用的方法,例如 WithByID 這種幾乎是每個(gè)實(shí)體都會(huì)有的方法,我們就不用重復(fù)寫了。
  • 最小化: 這么修改了之后,拆分組合更加方便了,很多查詢條件都可以最小化,例如我們可以添加一個(gè) WithSelects 的方法,我們?cè)?usecase 調(diào)用的時(shí)候就可以傳入當(dāng)前場(chǎng)景只需要關(guān)注的字段就可以了
  • 可測(cè)性: repo 層的測(cè)試會(huì)變得更加方便,這樣修改之后我們可以將查詢條件拆分出來(lái)進(jìn)行測(cè)試,會(huì)比之前耦合在一起測(cè)試簡(jiǎn)單很多。
  • 抽象: 這種方式可以讓我們抽象 CURD 接口更加方便

缺點(diǎn)

  • 最大的缺點(diǎn)就是有的問(wèn)題在單測(cè)可能測(cè)試不出來(lái)了,usecase 的測(cè)試中,repo 層被 mock 掉了,repo 在測(cè)試的時(shí)候大部分我們只會(huì)測(cè)試當(dāng)前的方法,所以 usecase 有使用比較復(fù)雜的查詢語(yǔ)句的時(shí)候,repo 測(cè)試最好測(cè)一測(cè)真實(shí)的使用場(chǎng)景,不要僅測(cè)試單個(gè) Option 方法

今天的文章就到這里,下篇文章給大家介紹一下 API 定義上的一點(diǎn)小技巧

本文轉(zhuǎn)載自微信公眾號(hào)「mohuishou」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系mohuishou公眾號(hào)。

原文鏈接:https://lailin.xyz/post/operator-09-kubebuilder-code.html

 

責(zé)任編輯:武曉燕 來(lái)源: mohuishou
相關(guān)推薦

2021-01-04 07:57:07

C++工具代碼

2019-09-20 15:47:24

代碼JavaScript副作用

2022-03-11 12:14:43

CSS代碼前端

2021-12-24 09:00:43

Go語(yǔ)言進(jìn)程

2020-05-14 09:15:52

設(shè)計(jì)模式SOLID 原則JS

2021-03-19 07:23:23

Go架構(gòu)Go工程化

2023-09-15 10:33:45

前端工程化commit

2021-06-05 18:01:05

工具Rollup前端

2021-12-07 08:16:34

React 前端 組件

2021-07-06 10:03:05

軟件開發(fā) 技術(shù)

2019-12-24 10:40:53

Java代碼編程

2024-03-28 14:29:46

JavaScript編程

2024-12-04 15:10:21

2020-05-08 14:45:00

JS代碼變量

2021-11-22 06:17:26

npm工程化工具

2018-07-12 14:20:33

SQLSQL查詢編寫

2023-11-02 09:02:55

Java模式

2021-11-08 07:48:48

Go語(yǔ)言對(duì)象

2022-12-01 07:46:01

工程化工具

2018-12-27 09:00:00

Java代碼編程語(yǔ)言
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)