减少Golang中依赖性注入的通用结构(附实例)

107 阅读2分钟

假设你有一个服务类,它依赖于两个数据库存储库类。这就要求你在服务结构中存储这两个类。这对于少量的依赖关系来说是可以的,但如果你需要更多的依赖关系,你就会有一个大的结构和混乱的代码来处理。你可能会让其他的服务做同样的事情,但是为不同的资源库类。最后,你会有很多重复的东西在那里。解决这个问题的方法很简单。我们将创建一个主资源库结构,将所有其他/子资源库的接口存储在其中。我们只需在我们需要的地方使用主资源库。这将使我们能够访问所有的嵌入式资源库。这有点像策略模式。

结构

├── cmd
│   └── client
│       └── main.go
└── internal
    ├── dao
    │   ├── article.go
    │   └── label.go
    ├── repository
    │   ├── article.go
    │   ├── label.go
    │   └── repository.go
    └── service
        ├── article.go
        └── label.go

文件

dao/article.go

package dao

import "time"

type ArticleRepository interface {
	Insert(article *Article) error
	Find(ID string) (*Article, error)
}

type Article struct {
	ID          string
	Title       string
	PublishedAt time.Time
}

dao/label.go

package dao

type LabelRepository interface {
	Insert(label *Label) error
	List(limit uint8) ([]*Label, error)
}

type Label struct {
	ID   string
	Name string
}

repository/repository.go

package repository

import "github.com/you/client/internal/dao"

type Repository struct {
	Article dao.ArticleRepository
	Label   dao.LabelRepository
}

func New() Repository {
	return Repository{
		Article: article{},
		Label:   label{},
	}
}

存储库/文章.go

package repository

import (
	"log"

	"github.com/you/client/internal/dao"
)

type article struct{}

func (a article) Insert(article *dao.Article) error {
	log.Println("inserting article")
	return nil
}

func (a article) Find(ID string) (*dao.Article, error) {
	log.Println("finding article")
	return nil, nil
}

仓库/标签.go

package repository

import (
	"log"

	"github.com/you/client/internal/dao"
)

type label struct{}

func (l label) Insert(label *dao.Label) error {
	log.Println("inserting label")
	return nil
}

func (l label) List(limit uint8) ([]*dao.Label, error) {
	log.Println("listing labels")
	return nil, nil
}

service/article.go

package service

import (
	"github.com/you/client/internal/dao"
	"github.com/you/client/internal/repository"
)

type Article struct {
	repo repository.Repository
}

func NewArticle(repo repository.Repository) Article {
	return Article{repo: repo}
}

func (a Article) DoSomething() {
	_ = a.repo.Article.Insert(&dao.Article{})
	_, _ = a.repo.Article.Find("id")
}

服务/label.go

package service

import (
	"github.com/you/client/internal/dao"
	"github.com/you/client/internal/repository"
)

type Label struct {
	repo repository.Repository
}

func NewLabel(repo repository.Repository) Label {
	return Label{repo: repo}
}

func (l Label) DoSomething() {
	_ = l.repo.Label.Insert(&dao.Label{})
	_, _ = l.repo.Label.List(1)
}

main.go

package main

import (
	"github.com/you/client/internal/repository"
	"github.com/you/client/internal/service"
)

func main() {
	repo := repository.New()

	articleService := service.NewArticle(repo)
	articleService.DoSomething()

	labelService := service.NewLabel(repo)
	labelService.DoSomething()
}

测试

$ go run -race cmd/client/main.go
2020/12/22 23:26:14 inserting article
2020/12/22 23:26:14 finding article
2020/12/22 23:26:14 inserting label
2020/12/22 23:26:14 listing labels