You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go实现解耦项目结构并复用main.go初始化变量的方案问询

实现类Django解耦结构的Go项目方案

核心思路:用显式依赖替代全局变量

Go的设计哲学更推崇显式依赖注入,这既能保持模块独立性,又能避免全局变量带来的耦合问题,完美适配你想要的类Django模块化结构。

1. 抽离核心依赖层

把DB连接这类全局依赖抽离到独立的内部包(比如internal/db),通过构造函数返回实例,由main包控制其生命周期:

// internal/db/db.go
package db

import (
    "database/sql"
    _ "github.com/lib/pq"
)

type DB struct {
    *sql.DB
}

func NewDB(connStr string) (*DB, error) {
    sqlDB, err := sql.Open("postgres", connStr)
    if err != nil {
        return nil, err
    }
    if err := sqlDB.Ping(); err != nil {
        return nil, err
    }
    return &DB{sqlDB}, nil
}

2. 模块化App的依赖注入设计

每个业务模块(比如planner)的Handler和Model都通过构造函数接收依赖,而非直接引用全局变量:

定义模块的Model与Handler

// cmd/planner/model.go
package planner

import "your-project/internal/db"

type PlannerModel struct {
    db *db.DB
}

// 通过构造函数注入DB实例
func NewPlannerModel(db *db.DB) *PlannerModel {
    return &PlannerModel{db: db}
}

// 示例业务方法
func (m *PlannerModel) GetPlan(id int) (Plan, error) {
    // 使用m.db执行数据库操作
}
// cmd/planner/handlers.go
package planner

import "net/http"

type PlannerHandlers struct {
    model *PlannerModel
}

// 注入Model实例,间接获取DB依赖
func NewPlannerHandlers(model *PlannerModel) *PlannerHandlers {
    return &PlannerHandlers{model: model}
}

// 示例Handler
func (h *PlannerHandlers) GetPlanHandler(w http.ResponseWriter, r *http.Request) {
    // 调用h.model处理业务逻辑
}

在main中组装所有模块

在cmd/api/main.go中完成依赖初始化,然后注入到各个模块,最后注册中心路由:

// cmd/api/main.go
package main

import (
    "net/http"
    "your-project/internal/db"
    "your-project/cmd/planner"
)

func main() {
    // 初始化DB连接
    dbConn, err := db.NewDB("postgres://user:pass@localhost/db")
    if err != nil {
        panic(err)
    }
    defer dbConn.Close()

    // 初始化planner模块的实例,注入依赖
    plannerModel := planner.NewPlannerModel(dbConn)
    plannerHandlers := planner.NewPlannerHandlers(plannerModel)

    // 中心路由注册(类似Django的urls.py)
    mux := http.NewServeMux()
    mux.HandleFunc("/planner/plan", plannerHandlers.GetPlanHandler)

    // 启动服务
    http.ListenAndServe(":8080", mux)
}

3. 测试友好的设计

依赖注入的模式让测试变得简单,只需替换为Mock实例即可:

// cmd/planner/model_test.go
package planner

import (
    "testing"
    "your-project/internal/db/mocks" // 用mockgen生成的MockDB
)

func TestGetPlan(t *testing.T) {
    // 创建MockDB实例并配置预期行为
    mockDB := mocks.NewDB(t)
    mockDB.ExpectQuery("SELECT ...").WillReturnRows(...)

    // 注入MockDB到Model
    model := NewPlannerModel(mockDB)
    // 执行测试逻辑
    plan, err := model.GetPlan(1)
    if err != nil {
        t.Fatal(err)
    }
    // 断言结果
}

4. 避免解耦破坏的注意事项

  • 模块内部不要自行初始化依赖,所有依赖由上层注入
  • 模块间尽量通过接口交互(比如定义DBer接口让PlannerModel依赖,而非具体的db.DB类型),进一步降低耦合
  • 中心路由只负责注册Handler,不处理业务逻辑,保持路由层简洁

内容的提问来源于stack exchange,提问作者Msw Tm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 15:45:33