首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Go中解耦的项目结构,并且仍然使用在main.go中初始化的变量用于其他包和测试?

在Go中解耦的项目结构,并且仍然使用在main.go中初始化的变量用于其他包和测试?
EN

Stack Overflow用户
提问于 2022-07-22 06:44:17
回答 2查看 181关注 0票数 5

我将转到Python/Django。在Django中,我非常喜欢它的模块化应用程序项目结构设计,每个应用程序都有不同的商务模型、路线和视图。然后,所有的应用程序都会在中央/项目的主路由系统内进行通信,等等。

Django项目结构,例如:

代码语言:javascript
复制
- myproject
    - myproject
        - urls.py
        - views.py
        ...
    - planner
        - urls.py
        - views.py
        - models.py
        ...

我正试图在Go项目中实现类似的项目设计:

代码语言:javascript
复制
    - myproject
        - cmd
            - api
                - main.go
                - routes.go
                - handlers.go
            - planner
                - routes.go
                - handlers.go
                - models.go

摘自cmd/api/main.go:

代码语言:javascript
复制
package main

...

db, err := sql.Open("pgx", cfg.db.dsn)
...
srv := &http.Server{
    Addr:         fmt.Sprintf("localhost:%d", app.config.port),
    Handler:      app.routes()
}
...

摘自cmd/api/ from .cmd:

代码语言:javascript
复制
package main

func (app *application) routes() *httprouter.Router {
    router := httprouter.New()

    planner.Routes(router)

    return router
}

节选自cmd/planner/常规。开始:

代码语言:javascript
复制
package planner
...
func Routes(router *httprouter.Router) {
    router.HandlerFunc(http.MethodPost, "/v1/planner/todos", CreateTodoHandler)
}

摘自cmd/planner/models.go.开始:

代码语言:javascript
复制
package planner

type PlannerModel struct {
    DB *sql.DB
}

func (p PlannerModel) InsertTodo(todo *Todo) error {
    query := `INSERT INTO todos (title, user_id)
    VALUES ($1, $2)
    RETURNING id, created_at`

    return p.DB.QueryRow(query, todo.Title, todo.UserID).Scan(&todo.ID, &todo.CreatedAt)
}

现在的问题是,我需要使用cmd/api/main.go文件中从package main初始化的DB连接到cmd/planner/handlers.go。由于变量来自主包,所以我无法将它导入应用程序的(计划程序)处理程序函数中。

代码语言:javascript
复制
package planner

func CreateTodoHandler(w http.ResponseWriter, r *http.Request) {
    var input struct {
        Title  string `json:"title"`
        UserID int64  `json:"user_id"`
    }

    err := helpers.ReadJSON(w, r, &input)
    ...
    todo := &Todo{
        Title:  input.Title,
        UserID: input.UserID,
    }
    ...
    // How to use/inject DB connection dependency into the PlannerModel?
    pm := PlannerModel{
        DB:    // ????
    } 

    err = pm.InsertTodo(todo)
    ...
}

我认为有一个全局DB变量可以解决这个问题,或者我找到的一个合理的answer是在一个单独的包中声明这个变量,并在main.go中初始化它。另一种方法是让Planner/handlers.go属于package main,并在主包中创建一个application结构,以保存项目的所有模型并在处理程序中使用它,但我想这将挫败解耦的体系结构设计。

我想知道什么是首选的方法,或者是否有更好的方法来实现类似的解耦项目结构(如Django ),并且仍然将main.go中的变量初始化到其他包中并进行测试?

EN

回答 2

Stack Overflow用户

发布于 2022-07-26 10:22:26

当我从Python/Django转到Go时,我也有过类似的经历。

在每个应用程序中访问db连接的解决方案是在每个具有db连接字段的应用程序中定义结构,然后主要创建db连接和所有应用程序结构。

代码语言:javascript
复制
// planner.go

func (t *Todo) Routes(router *httprouter.Router) {
    router.HandlerFunc(http.MethodPost, "/v1/planner/todos", t.CreateTodoHandler)
}
代码语言:javascript
复制
// handlers.go

struct Todo {
    DB: *sql.DB
}

func (t *Todo) CreateTodo(w http.ResponseWriter, r *http.Request) {
    var input struct {
        Title  string `json:"title"`
        UserID int64  `json:"user_id"`
    }

    err := helpers.ReadJSON(w, r, &input)
    ...
    todo := &Todo{
        Title:  input.Title,
        UserID: input.UserID,
    }
    ...

    pm := PlannerModel{
        DB: t.DB
    } 

    err = pm.InsertTodo(todo)
    ...
}

这将解决您当前的问题,但如果您没有更好的应用程序设计,则会出现其他问题。

建议阅读这两篇博文,以便更好地理解Go中的应用程序设计和代码结构。

https://www.gobeyond.dev/standard-package-layout/

https://www.gobeyond.dev/packages-as-layers/

票数 3
EN

Stack Overflow用户

发布于 2022-07-26 17:41:52

我的方法是在DI中使用干净的架构。

存储库构造函数示例:https://github.com/zubroide/go-api-boilerplate/blob/master/model/repository/user_repository.go#L16-L19

使用db连接声明存储库的示例:https://github.com/zubroide/go-api-boilerplate/blob/master/dic/app.go#L58-L63

在服务声明中使用存储库的示例:https://github.com/zubroide/go-api-boilerplate/blob/master/dic/app.go#L65-L70

这与其他DI类似,例如wire

优点是:

  • 没有循环依赖关系的问题,
  • 简化了服务依赖项支持.
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73076117

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档