近期在公司实习,参与了公司的一个分布式的应用服务系统。系统采用 Golang 语言作为系统的开发语言,在开发过程中采用了 Go 语言的反射函数的特性来取代了以前常使用的 switch 语法。
Web 应用路由问题
在我们编写 Web 应用过程中,常常会遇到一个路由需要对应一个方法,我们会选择使用 switch 的方法来进行路由的匹配,若是路由匹配成功,我们会调用一个方法,这种方法能够很简便的完成我们的工作,也便于程序员在编写代码过程中厘清思路。
问题:
在一个 URL 的路由中,我们在 request 中通过 cmd 的参数来对应一个方法,这样我们要如何根据一个 cmd 对应一个方法?
可能针对这个问题有人会说,我们为什么不把 cmd 放到 URL 里面,这样的话就是一个方法对应一个路由,而且大多数的 Web 框架会通过回调函数来进行函数调用,针对于这个问题,我只能说大部分的都是将 cmd 放到 http 的 request 里面的,具体的好处可能就是减少了对 API 的监管,以及当路由比较多的时间能够减少麻烦吧。
用 switch 方法实现:
上述的方法先通过 URL 的参数获取到 cmd,然后通过 cmd 来调用相对应的方法。在传统的 MVC 的设计模式中,需要在Controller 中添加 switch 方法,同时需要在 Model 中实现相对应的方法,总计修改了2个文件。
go 语言反射函数
reflect 包
在 reflect 包中,主要通过 Typeof() 和 Valueof() 两个方法来实现反射。两个方法相互结合,能够反射出被反射函数的全部信息。
TypeOf()
TypeOf() 函数主要是打印出被反射函数的类型,其返回结果是 reflect.Type 类型。
在上面的示例中,通过 Method().Name 能够反射其方法的函数名。
常用的方法:
-
func (t *rtype)String() string
-
func (t *rtype)Name() string
-
func (t *rtype)Kind() reflect.kind
-
func (t *rtype)Method(int) reflect.Method
-
func (t *rtype)Elem() reflect.Type
-
func (t *rtype)In(int) reflect.Type
ValueOf()
ValueOf() 函数主要是打印出被反射函数的类型,其返回结果是 reflect.Value 类型。
在上面的示例中,通过 Method().Call() 能够反射出其函数并执行。
常用的方法:
-
func (v Value)String() string
-
func (v Value)Elem() reflect.Value
-
func (v Value)Method(int) reflect.Value
-
func (v Value)Call(in []Value) (r []Value)
反射的实现过程
由于有反射的存在,因此在传统的 MVC 的设计模式中,当我们添加服务时,不需要修改 Controller 端的代码,Controller 只需要维持一个 map 的表,里面的就来存储需要被反射的 models。
在上诉的例子中,通过对 services 的服务注册,就能够通过 Start() 函数发现服务,并且根据业务来实现自己的代码。
因此在我们主函数中,导入封装好的包,只需要注册一个结构体,就能够将自己的方法反射出来实现。
对应上面的 Web 的路由问题,我们将 Controller 进行封装,然后将 Model 进行反射,当我们业务增加时,我们在 Model里面添加就可以了,不需要修改 Controller。