​ 在了解了项目结构后,会明白我们往往会在Module后放入用户的功能,但是不同的功能实现涉及不同的理念,在小项目的时候,往往就是一坨功能合在一起,但是功能多起来了的时候,应该怎么实现?

先看看我一开始的代码:

1
2
3
4
5
6
7
8
// main.go
func main(){
r := gin.Default()
log.Init()
configs.Init()
db.Init()
routers.RootPath(r)
}
1
2
3
4
5
6
7
// routers.go 自成一个包
func RootPath(r *gin.Engine){
rootPath := r.Group("/user"){
r.POST("/register",Register)
r.POST("/update",middleware.Auth(),Update)
}
}
1
2
3
// 具体功能实现 user
update.go
register.go...

学习了NX的模板,才发现自己以前写功能实现就是一坨

NX的模板进行了更好的封装以及通用化处理

下面先看一下结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|-cmd  
|-server
|-server.go
|-internal
|-module
|-user.go
|-login.go
|-init.go
|-routers.go
|-update.go
|-login.go
|-read.go
|- 其他的包 --实现其他的功能
|-module.go
|-main.go
1
2
3
4
5
// main.go
func main(){
server.Init() //启动服务 db,config
server.Run() //log,recovery,router的运行
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// server.go
func Init(){
configs.Init()
db.Init()
for _ , m:=range Module{
fmt.Println("Init Module:" + m.GetName())
m.Init() // 可以实现功能包的Init处理,结构配置什么的
}
}

func Run(){
r := gin.New()
r.use(log.Init(),middleware.Recovery())

for _,m:=range module.Module{
fmt.Printlun("InitRouter: "+m.GetName())
m.InitRouter(r.Group("/"+m.GetName())) // 这边相当于充当了一个r.Group的实现
}
}

功能的NX实现来了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// module.go
// 定义一个接口 -- 每个功能都需要其方法
func Module interface{}{
GetName()string
Init()
InitRouter(r *gin.RouterGroup)
}

// 定义一个通用的Module切片,来存储相应的“功能”
var Modules []Module

// 添加路由
func RegisterModule(m Module){
Modules = append(Modules,m)
}

// init函数会在程序运行前做必要的初始化工作
func init(){
RegisterModule(&user.ModuleUser{})
}

GetName()实现了吧这个包的name传给了对应的r.Group

1
2
3
4
5
6
7
8
9
// user/init.go
//为了区分相应的功能,可以将Module变成对应的类型
type ModuleUser struct{}

func (u *ModuleUser)GetName() string{
return "user"
}
//其中可以加上相应的配置组合
func (u *ModuleUser)Init(){}

对于空接口来说,什么类型都能够传入

对于有方法的接口来说,那么实现了其全部方法的类型就能够传入

所以可以吧 type ModuleUser struct{} 定义,只要ModuleUser实现了三个方法Init/InitRouter/GetName

1
2
3
4
5
6
7
8
// user/routers.go
func (u *ModuleUser) InitRouter(r *gin.RouterGroup){
r.POST("/register",Register)
r.POST("/login", Login)
r.PUT("/update", middleware.Auth(), Update)
r.GET("/read", middleware.Auth(), Read)
r.DELETE("/delete", middleware.Auth(), Delete)
}

​ 神奇,能够发现的是真正好的代码往往使用方法接口的方式实现封装,在层层的封装下,实现通用化,在新增一个功能的情况下,只要专注于相应的功能实现,其他包中的Init实现都可以照抄

​ 类似于,一坨shi山,以前的我新增一个功能相当于直接一坨扔进去,而NX相当于把一坨一点点涂上去,太优雅了。