不太一样的Go Web框架—编程范式 - aaayi
source link: https://www.cnblogs.com/codexiaoyi/p/16153914.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
不太一样的Go Web框架—编程范式
项目地址:https://github.com/Codexiaoyi/linweb
这是一个系列文章:
上文说过,linweb不追求性能,相比而言注重编程范式。本人也是dotneter,个人觉得.net那种注解定义路由的方式更为舒服,并且接口文件统一规定在Controller文件夹下,以 XxxController 命名。
当然,在Go中也是可以实现这样的方式,但是将用到大量反射,所以势必会降低性能,所以说"不太一样的Web框架"。
所谓编程范式,也就是你的框架定义规范,使用用户按照你的规范写逻辑业务。
路由解析是一个web框架不可避免的模块,我们看gin是如何定义路由的。
func main() {
router := gin.Default()
// Simple group: v1
v1 := router.Group("/v1")
{
v1.POST("/login", loginEndpoint)
v1.POST("/submit", submitEndpoint)
v1.POST("/read", readEndpoint)
}
// Simple group: v2
v2 := router.Group("/v2")
{
v2.POST("/login", loginEndpoint)
v2.POST("/submit", submitEndpoint)
v2.POST("/read", readEndpoint)
}
router.Run(":8080")
}
在应用gin的时候,我们通常会将路由定义与接口方法对应写在一起,统一管理,这样管理方便,也是Go的web框架多数采用的方式。
相比之下,linweb更希望路由定义和方法放在一起,然后以定义Controller的方式,路由地址更加直观。
package controllers
import (
"github.com/Codexiaoyi/linweb/interfaces"
)
type BlogController struct {
}
//[GET("/blog/:id")]
func (blog *BlogController) GetBlog(c interfaces.IContext) {
}
在根目录下创建一个 controllers 文件夹,所有的api都定义在controllers包中。根据不同的 controller 名称区分文件。
自定义插件
linweb中所有功能与主流程间的依赖都是解耦的,所有实现都面向接口,完全遵守依赖倒置原则。
要实现这样的方式也不难:
- 定义一套接口,使得实现相应接口的结构体都可以运行在linweb中。
- 完成默认实现,默认应用默认实现在linweb中。
- 开放传入自定义插件实现的方法。
在Go语言框架中大量使用Option模式实现上述的需求(完整代码详见github)。
1.首先我们定义一个自定义插件类型,并写一个默认的插件函数。
//自定义插件类型,返回可以传入Linweb的函数
type CustomizePlugins func(lin *Linweb)
func defaultPlugins() CustomizePlugins {
return func(lin *Linweb) {
lin.markRouter = router.New()
lin.markContext = &context.Context{}
lin.markMiddleware = &middleware.Middleware{}
lin.markInject = injector.Instance()
lin.markCache = cache.Instance()
lin.markModel = &model.Model{}
}
}
2.定义各个插件模块对应的快捷入口函数。
// Customize router plugin.这里参数传入自定义的Router实现
func RouterPlugin(router interfaces.IRouter) CustomizePlugins {
return func(lin *Linweb) {
lin.markRouter = router
}
}
// Customize context plugin.
func ContextPlugin(context interfaces.IContext) CustomizePlugins {
return func(lin *Linweb) {
lin.markContext = context
}
}
......
3.在linweb包的New初始化函数中,传入用户自定义的CustomizePlugins。
// Create a new Linweb.
// Add customize plugins with method of plugins.go, otherwise use default plugins.
func NewLinweb(plugins ...CustomizePlugins) *Linweb {
lin := &Linweb{}
//应用默认插件
defaultPlugins()(lin)
//根据传入的用户自定义插件覆盖默认插件
for _, plugin := range plugins {
plugin(lin)
}
pluginsModel = lin.markModel
Cache = lin.markCache
return lin
}
在linweb项目中的linweb_test.go中,用到了mock框架(后续测试部分会介绍)模拟接口实现:
// Arrange:mock data
ctrl := gomock.NewController(t)
defer ctrl.Finish()
// mock a new context instance
mock_context := mocks.NewMockIContext(ctrl)
//Act
linweb := NewLinweb(ContextPlugin(mock_context))
如代码所见,我们调用linweb的ContextPlugin函数传入自定义插件,再将返回值传入NewLinweb初始化函数中。
本文,介绍了linweb的基本的编程范式,也实现了自定义插件功能。
接下来,我们需要根据前文说的功能逐步添加到linweb中。
Recommend
-
58
-
31
该系列会有 3 篇文章,分别介绍什么是函数式编程、剖析函数式编程库、以及函数式编程在 React 中的应用,欢迎关注我的
-
80
该系列会有 3 篇文章,分别介绍什么是函数式编程、剖析函数式编程库、以及函数式编程在 React 中的应用,欢迎关注我的 'blog' 命令式编程和声明式编程 拿泡茶这个事例进行区分命令式编程和声明式
-
41
-
21
dvajs 是 Alibaba 针对于 react/redux 技术栈基于 elm 概念编写的一套脚手架。 <!-- more --> 两年前因为 antd 开始接触了这套脚手架。我的确很需要这套脚手架,对于新手来说...
-
20
-
3
B站在日本走红的路子,和我们想的不太一样本文来自微信公众号:
-
8
我的音乐播放器可能跟你的不太一样 2021-07-14 听音乐是很正常的需求,市面上也有很多解决此类诉求的工具,比如 Apple Music 或者 Spotify,我之前用的比较多的是 Spotify,后来由于付款方式(不习惯将自己的账号密码让淘宝上...
-
4
欧洲,跟李斌想象中不太一样 在德国时间 10 月 7 日的 NIO Berlin 2022 活动现场,虎嗅记者对一位有宝马集团工作经验的...
-
1
苹果的人工智能应用,跟 ChatGPT 不太一样爱范儿·2023-05-01 05:46理念不合,暂不入局。苹果的 XR 混合现实设备,其中一...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK