避免 Golang 接口中的 getter 的变通解决方案
Workaround solution to avoid getters in Golang interface
感谢您花时间阅读这个问题!
我是 Golang 的新手,我一直在开发一个简单的社交媒体 API 来练习这门语言。在这个项目中,我使用一个结构来表示用户发布的 Post 的模型,如下所示:
// models/post.go
package models
import "time"
type Post struct {
ID uint64
Title string
Content string
AuthorID uint64
Likes uint64
CreatedAt time.Time
}
func (p *Post) ValidateFields() error {
// validate fields
}
这个 post 可以借助存储库中的方法保存到数据库中:
// repositories/posts.go
import (
"database/sql"
"models"
)
type PostsRepository struct {
db *sql.DB
}
func NewPostsRepository(db *sql.DB) *PostsRepository {
return &PostsRepository{db}
}
func (r *PostsRepository) Save(models.Post) (uint64, error) {
// Passing the model as a parameter
}
如您所见,模型作为参数传递,这感觉像是一个问题,原因有两个:
- 我只需要三个字段就可以将 post 保存到数据库(标题,
Content 和 AuthorID),因为其他所有内容都会生成
自动
- 如果我为保存函数编写单元测试,它将
依赖模型工作,因此模型有任何问题
会影响考试
考虑到这一点,我考虑将参数从模型更改为接口,但由于接口只接受方法签名,在这种特定情况下,我只需要属性来将数据保存在数据库中,我认为它会需要一些 getter,例如:
type PostInterface interface {
GetTitle() string
GetContent() string
GetAuthorID() uint64
}
(我知道将 getter 称为“GetAttribute”并不惯用,但这只是给你一个想法)
因此,我必须在我的 Post 模型上实现这三种方法,看起来像
func (p Post) GetTitle() string {
return p.Title
}
func (p Post) GetContent() string {
return p.Content
}
func (p Post) GetAuthorID() uint64 {
return p.AuthorID
}
这看起来不太好,但当我们去测试时情况会变得更糟。
就像我说的,我不想在测试中使用该模型,所以我必须创建一个结构来充当存根或仅具有保存工作所需的三个字段的东西(这听起来不错)。但是,我必须再次实现这三个方法,以便结构可以被保存函数接受为接口(这听起来很糟糕)
听起来好像有很多不必要的工作,有什么办法可以解决这个问题吗?我不确定我是否遗漏了关于 Go 的一些概念性的东西,或者我的架构是否有任何可以解决这个问题的变化,但我在寻找替代方案时遇到了麻烦
谢谢!
在保存函数中使用结构非常好并且被认为是惯用的。如果这只是一个数据容器,我在测试此功能时看不到任何问题。但是,您可以选择结构的精简版本,仅包含在数据库中存储内容时所需的相应字段。
例如:
type Content struct {
Title string
Content string
AuthorID uint64
}
如果您仍然想与接口分离,您可以在 Post
模型和 return Content 结构上创建一个方法,我个人认为没有必要这样做,因为它会使用另一层抽象不会提高可测试性,只会增加复杂性。
在您的测试中,您可以创建 Content struct
的一个实例并将其传递给 Save
函数。
感谢您花时间阅读这个问题!
我是 Golang 的新手,我一直在开发一个简单的社交媒体 API 来练习这门语言。在这个项目中,我使用一个结构来表示用户发布的 Post 的模型,如下所示:
// models/post.go
package models
import "time"
type Post struct {
ID uint64
Title string
Content string
AuthorID uint64
Likes uint64
CreatedAt time.Time
}
func (p *Post) ValidateFields() error {
// validate fields
}
这个 post 可以借助存储库中的方法保存到数据库中:
// repositories/posts.go
import (
"database/sql"
"models"
)
type PostsRepository struct {
db *sql.DB
}
func NewPostsRepository(db *sql.DB) *PostsRepository {
return &PostsRepository{db}
}
func (r *PostsRepository) Save(models.Post) (uint64, error) {
// Passing the model as a parameter
}
如您所见,模型作为参数传递,这感觉像是一个问题,原因有两个:
- 我只需要三个字段就可以将 post 保存到数据库(标题, Content 和 AuthorID),因为其他所有内容都会生成 自动
- 如果我为保存函数编写单元测试,它将 依赖模型工作,因此模型有任何问题 会影响考试
考虑到这一点,我考虑将参数从模型更改为接口,但由于接口只接受方法签名,在这种特定情况下,我只需要属性来将数据保存在数据库中,我认为它会需要一些 getter,例如:
type PostInterface interface {
GetTitle() string
GetContent() string
GetAuthorID() uint64
}
(我知道将 getter 称为“GetAttribute”并不惯用,但这只是给你一个想法)
因此,我必须在我的 Post 模型上实现这三种方法,看起来像
func (p Post) GetTitle() string {
return p.Title
}
func (p Post) GetContent() string {
return p.Content
}
func (p Post) GetAuthorID() uint64 {
return p.AuthorID
}
这看起来不太好,但当我们去测试时情况会变得更糟。 就像我说的,我不想在测试中使用该模型,所以我必须创建一个结构来充当存根或仅具有保存工作所需的三个字段的东西(这听起来不错)。但是,我必须再次实现这三个方法,以便结构可以被保存函数接受为接口(这听起来很糟糕)
听起来好像有很多不必要的工作,有什么办法可以解决这个问题吗?我不确定我是否遗漏了关于 Go 的一些概念性的东西,或者我的架构是否有任何可以解决这个问题的变化,但我在寻找替代方案时遇到了麻烦
谢谢!
在保存函数中使用结构非常好并且被认为是惯用的。如果这只是一个数据容器,我在测试此功能时看不到任何问题。但是,您可以选择结构的精简版本,仅包含在数据库中存储内容时所需的相应字段。
例如:
type Content struct {
Title string
Content string
AuthorID uint64
}
如果您仍然想与接口分离,您可以在 Post
模型和 return Content 结构上创建一个方法,我个人认为没有必要这样做,因为它会使用另一层抽象不会提高可测试性,只会增加复杂性。
在您的测试中,您可以创建 Content struct
的一个实例并将其传递给 Save
函数。