我正在尝试使用 Go 遵循Clean Architecture。该应用程序是一个简单的图像管理应用程序。
我想知道如何最好地为我的存储库层设计接口。我不想将所有存储库方法组合到一个大接口中,就像我发现的一些示例那样,我认为在 Go 中通常首选小接口。我不认为有关管理图像的用例代码需要知道存储库还存储用户。所以我想有UserReader
,UserWriter
和ImageReader
。ImageWriter
复杂的是代码需要是事务性的。事务管理属于 Clean Architecture 存在一些争论,但我认为用例层需要能够控制事务。我认为,属于单个事务的是业务规则,而不是技术细节。
现在的问题是,如何构造接口?
所以在这种方法中,我打开一个事务,运行提供的函数并在没有错误的情况下提交。
type UserRepository interface {
func ReadTransaction(txFn func (UserReader) error) error
func WriteTransaction(txFn func (UserWriter) error) error
}
type ImageRepository interface {
func ReadTransaction(txFn func (ImageReader) error) error
func WriteTransaction(txFn func (ImageWriter) error) error
}
问题:不,我不能在单个事务中轻松地编写用户和图像,我必须UserImageRepository为此创建一个额外的接口并提供一个单独的实现。
事务作为存储库
type ImageRepository interface {
func Writer() ImageReadWriter
func Reader() ImageReader
}
我认为这与功能方法非常相似。它不会解决联合使用多个存储库的问题,但至少可以通过编写一个简单的包装器来实现。
一个实现可能是这样的:
type BoltDBRepository struct {}
type BoltDBTransaction struct { *bolt.Tx }
func (tx *BoltDBTransaction) WriteImage(i usecase.Image) error
func (tx *BoltDBTransaction) WriteUser(i usecase.User) error
....
不幸的是,如果我实现这样的交易方法:
func (r *BoltDBRepository) Writer() *BoltDBTransaction
func (r *BoltDBRepository) Reader() *BoltDBTransaction
因为这没有实现ImageRepository接口,所以我需要一个简单的包装器
type ImageRepository struct { *BoltDBRepository }
func (ir *ImageRepository) Writer() usecase.ImageReadWriter
func (ir *ImageRepository) Reader() usecase.ImageReader
作为价值的交易
type ImageReader interface {
func WriteImage(tx Transaction, i Image) error
}
type Transaction interface {
func Commit() error
}
type Repository interface {
func BeginTransaction() (Transaction, error)
}
存储库实现看起来像这样
type BoltDBRepository struct {}
type BoltDBTransaction struct { *bolt.Tx }
// implement ImageWriter
func (repo *BoltDBRepository) WriteImage(tx usecase.Transaction, img usecase.Image) error {
boltTx := tx.(*BoltDBTransaction)
...
}
问题:虽然这可行,但我必须在每个存储库方法的开头键入断言,这看起来有点乏味。
所以这些是我可以想出的方法。哪个最合适,或者有更好的解决方案?
白板的微信
哆啦的时光机
幕布斯6054654
相关分类