关于控制器的优化
首先从代码功能分析,这个控制器像由两部分组成。一部分是业务逻辑,也就是 time.Sleep 函数所代表的逻辑,在实际生产过程中,这里会有很重的业务逻辑代码;而另一部分是非业务逻辑,比如创建 Context、通道等待 finish 信号等。
很明显,这个非业务逻辑是非常通用的需求,可能在多个控制器中都会使用到。而且考虑复用性,这里只是写了一个控制器,那如果有多个控制器呢,我们难道要为每个控制器都写上这么一段超时代码吗?那就非常冗余了。
所以,设计一个机制,将这些非业务逻辑代码抽象出来,封装好,提供接口给控制器使用。这个机制的实现,就是中间件。
代码的组织顺序很清晰,先预处理请求,再处理业务逻辑,最后处理返回值,你发现没有这种顺序,其实很符合设计模式中的装饰器模式。装饰器模式,顾名思义,就是在核心处理模块的外层增加一个又一个的装饰,类似洋葱。
抽象出中间件的思路是不是就很清晰了,把核心业务逻辑先封装起来,然后一层一层添加装饰,最终让所有请求正序一层层通过装饰器,进入核心处理模块,再反序退出装饰器
使用函数嵌套方式实现中间件
装饰器模式是一层一层的,所以具体实现其实也不难想到,就是使用函数嵌套。首先,我们封装核心的业务逻辑。就是说,这个中间件的输入是一个核心的业务逻辑 ControllerHandler,输出也应该是一个 ControllerHandler。所以对于一个超时控制器,我们可以定义一个中间件为 TimeoutHandler。
使用 pipeline 思想改造中间件
一层层嵌套不好用,如果我们将每个核心控制器所需要的中间件,使用一个数组链接(Chain)起来,形成一条流水线(Pipeline),就能完美解决这两个问题了
Middleware 不再以下一层的 ControllerHandler 为参数了,它只需要返回有自身中间件逻辑的 ControllerHandler。
将每个中间件构造出来的 ControllerHandler 和最终的业务逻辑的 ControllerHandler 结合在一起,成为一个 ControllerHandler 数组,也就是控制器链。在最终执行业务代码的时候,能一个个调用控制器链路上的控制器。
因为中间件中创造出来的 ControllerHandler 匿名函数,和最终的控制器业务逻辑 ControllerHandler,都是同样的结构,所以我们可以选用 Controllerhander 的数组,来表示某个路由的业务逻辑。
index 下标表示当前调用 Next 要执行的控制器序列,它的初始值应该为 -1,每次调用都会自增 1,这样才能保证第一次调用的时候 index 为 0,定位到控制器链条的下标为 0 的控制器,即第一个控制器。