Я предполагаю, что ваш main_package
не является пакетом main
в Go. Я думаю, что 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
}
На мой взгляд, это мощный шаблон, поскольку вы можете написать более «универсальные» обработчики и просто подключить их к нужным вам маршрутам.
person
Pie 'Oh' Pah
schedule
11.12.2015
child_package
, а child_package снова будет вызыватьhandler package
. Проблема не решена с новым пакетом обработчика. - person Mahesh Haldar   schedule 11.12.2015