为了账号安全,请及时绑定邮箱和手机立即绑定

具有多个子包的 gorilla mux 路由中的循环导入问题

具有多个子包的 gorilla mux 路由中的循环导入问题

Go
千巷猫影 2021-11-29 15:51:45
这是我的项目结构--主包---|--child_package1---|--child_package2---|--child_package3我有 main_package 中列出的 API 调用的所有路由和方法调用管理main_package.go 中的路由器处理程序如下所示:func Handlers(db *sql.DB, customeruploadFile string) *mux.Router {  router := mux.NewRouter()  router.HandleFunc("/api1", child_package1.method )  router.HandleFunc("/api2", child_package2.method)  router.HandleFunc("/api3", child_package3.mehtod)  fileHandler := http.FileServer(http.Dir("./client/compiled"))  router.PathPrefix("/").Handler(http.StripPrefix("/", fileHandler))  return router}问题是当我为子包编写测试用例时,我需要这个 Handlers 方法来创建测试服务器,为此我需要在 child_packages 中导入 main_package,然后很明显有循环导入发生,因为 child_packages 在 main_package 中导入。任何人都可以建议我解决这个问题的最佳方法吗?
查看完整描述

1 回答

?
慕的地6264312

TA贡献1817条经验 获得超6个赞

我假设你main_package不是mainGo 中的包。我认为 child_packages 不应该在下面,main_package因为我们的目标是将每个包彼此分离。


这是我目前在我的项目中使用的模式来避免依赖冲突:


project/

├── main_package

│   └── main_package.go

├── brokers

│   └── brokers.go

├── child_package1

│   └── child_package1.go

├── child_package2

│   └── child_package2.go

└── child_package3

    └── child_package3.go

本质上,每个包都不应该处理自身之外的任何事情(或者至少尽可能少地处理)。该broker会是唯一的党的任何两个包之间谁“谈判中”。


// main_package.go

package main_package


import (

    "path/to/sql"

    "path/to/mux"

    "path/to/brokers"

)


// Never use selectors from packages directly

// but create a `Broker` object for each endpoint

var bk1 = brokers.New("/api1")

var bk2 = brokers.New("/api2")

var bk3 = brokers.New("/api3")


func Handlers(db *sql.DB, customeruploadFile string) *mux.Router {

    router := mux.NewRouter()


    // each broker has its own `MyHandler` function

    router.HandleFunc("/api1", bk1.MyHandler)

    router.HandleFunc("/api2", bk2.MyHandler)

    router.HandleFunc("/api3", bk3.MyHandler)


    fileHandler := http.FileServer(http.Dir("./client/compiled"))

    router.PathPrefix("/").Handler(http.StripPrefix("/", fileHandler))

    return router

}

该brokers包是用于通信的中央接口


// brokers.go

package brokers


import (

    "path/to/child_package1"

    "path/to/child_package2"

    "path/to/child_package3"

    "net/http"

)


type Broker interface {

    MyHandler(http.ResponseWriter, *http.Request) 

}


// Factory function to create a `Broker` instance

func New(uri string) Broker {

    if uri == "/api1" {

        return Broker( new(child_package1.Delegate) )

    } else if uri == "/api2" {

        return Broker( new(child_package2.Delegate) )

    } else if uri == "/api3" {

        return Broker( new(child_package3.Delegate) )

    }

    return nil

}

现在child_packageX不再与任何内部依赖解耦,只要它公开一个“代表”或Delegate对象来与经纪人交谈。


// child_package1.go

package child_package1


import "net/http"


type Delegate struct {

   // Optional parameters can be carried by the Delegate

   // to be used in the created Broker anywhere

}


func (d *Delegate) MyHandler(w http.ResponseWriter, r *http.Request) {

  // Maybe return a JSON here

}

每个孩子都可以有自己的MyHandler,为不同的 api 调用做不同的事情,而不必知道他们正在服务的端点。


// child_package2

package child_package2


import "net/http"


type Delegate struct {}


func (d *Delegate) MyHandler(w http.ResponseWriter, r *http.Request) {

    // Maybe return an XML here

}

在main_package不导入所有的child_packageX,只是在broker包。您可以编写一个导入broker包而不是实际包的测试,或者您甚至可以编写另一个代理进行测试。


package test


import (

    "testing"

    "path/to/main_package"

)


func TestMain(*testing.T) {

    // test the routing in `main_package`

}

您不再测试处理程序函数的功能,而是测试代理公开的端点之一。这鼓励您编写通用处理程序函数并专注于更高级别的端点。


package test


import (

    "testing"

    "path/to/broker"


)


func TestGetJSONAlright(*testing.T) {

     bk1 := brokers.New("/api1")

     // test if I get JSON here

}


func TestGetXMLAlright(*testing.T) {

    bk1 := brokers.New("/api2")

    // test if I get XML here

}

在我看来,这是一种强大的模式,因为您可以编写更多“通用”处理程序并将它们插入到您想要的路由中。


查看完整回答
反对 回复 2021-11-29
  • 1 回答
  • 0 关注
  • 128 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信