自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

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

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

[[442185]]

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

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

最簡單的方式,就是我們直接在 repo 這里寫兩個方法

  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) 

這樣最簡單也最直觀,但是問題是我們的實際的業(yè)務需求往往比我們的例子復雜,如果我們需要通過 id 或者標題獲取呢?再添加一個 GetArticleByIDOrTitle ?

這么做的話也不是不行,但是這么做的話就會讓我們的 repo 的代碼隨著時間的增長越來越多不說,命名也是問題,因為組合的方式可能是多種多樣的

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

DBOption

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

  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) 

我們定義一個的 DBOption 這個 Option 方法會作為我們 repo 層方法中的最后一個參數(shù),這樣我們在定義方法的時候就可以簡潔一些,就不必定義很多 GetArticleByXXX 方法了,而是通過定義很多 WithByXXX 的 Option 方法來解決。

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

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

優(yōu)點

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

  1. // GetArticle 和 GetAuthor 都能用上 
  2. func (u *article) GetArticle(ctx context.Context, id int) (*domain.Article, error) { 
  3.  // 這里可能有其他業(yè)務邏輯... 
  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è)務邏輯... 
  7.  return u.repo.GetAuthor(ctx, u.repo.WithByID(uint(id))) 

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

  1. // GetArticle 返回文章的同時也需要返回作者的名字 
  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 

可測性: repo 層的測試會變得更加方便,這樣修改之后我們可以將查詢條件拆分出來進行測試,會比之前耦合在一起測試簡單很多。

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

  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 

總結

今天給大家介紹了使用 Function Option 的方式來寫 repo 層的代碼,接下來我們就簡單總結一下

  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)點

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

缺點

  • 最大的缺點就是有的問題在單測可能測試不出來了,usecase 的測試中,repo 層被 mock 掉了,repo 在測試的時候大部分我們只會測試當前的方法,所以 usecase 有使用比較復雜的查詢語句的時候,repo 測試最好測一測真實的使用場景,不要僅測試單個 Option 方法

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

本文轉(zhuǎn)載自微信公眾號「mohuishou」,可以通過以下二維碼關注。轉(zhuǎn)載本文請聯(lián)系mohuishou公眾號。

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

 

責任編輯:武曉燕 來源: mohuishou
相關推薦

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語言進程

2021-03-19 07:23:23

Go架構Go工程化

2020-05-14 09:15:52

設計模式SOLID 原則JS

2021-06-05 18:01:05

工具Rollup前端

2023-09-15 10:33:45

前端工程化commit

2021-12-07 08:16:34

React 前端 組件

2021-07-06 10:03:05

軟件開發(fā) 技術

2024-03-28 14:29:46

JavaScript編程

2019-12-24 10:40:53

Java代碼編程

2024-12-04 15:10:21

2020-05-08 14:45:00

JS代碼變量

2021-11-22 06:17:26

npm工程化工具

2023-11-02 09:02:55

Java模式

2021-11-08 07:48:48

Go語言對象

2018-07-12 14:20:33

SQLSQL查詢編寫

2022-12-01 07:46:01

工程化工具

2018-12-27 09:00:00

Java代碼編程語言
點贊
收藏

51CTO技術棧公眾號