1.Golang 设计模式之装饰器模式
Golang 设计模式之装饰器模式
本期和大家交流的找鸡是设计模式中的装饰器模式。
装饰器模式的蛋源基本定义是:在不变更原对象结构的基础上,动态地为对象增加附属能力。码领码它与“继承”有一定的鸡蛋相似之处,但侧重点不同,小程序源可以将装饰器模式视为“继承”的找鸡中短通吃源码一种补充手段。
为了更好地理解装饰器模式,蛋源以下是码领码一个实际案例的分析:
通过编程的方式,我们可以还原上述场景问题。鸡蛋一种常见的小程序源实现方式是采用继承。然而,找鸡这种实现方式需要对子类的蛋源景点小程序源码等级和种类进行枚举,包括一系列一级和二级子类。码领码这种固定的鸡蛋等级架构存在一些问题。
因此,小程序源在这种“加料”场景中,使用继承的设计模式可能并不合适。我们可以改变思路,不再关注对所有组合种类的枚举,而是将注意力放在“加料”的过程中。
在这种实现思路下,就诞生了基于“装饰器模式”的实现架构。例如,golang websocket源码分析一份鸡蛋培根盖浇饭可以由一份白米饭(核心类)加上一份鸡蛋(装饰器1)和一份培根(装饰器2)组成,其中鸡蛋和培根的装饰顺序不限制。这样,无论后续有多少种新的“菜品”加入,我们只需声明其对应的装饰器类即可。
比如,双份鸡蛋盖浇饭 = 一份白米饭(核心类)+ 一份鸡蛋(装饰器1)+一份鸡蛋(装饰器1);鸡蛋火腿青椒盖浇饭 = 一份白米饭(核心类)+ 一份鸡蛋(装饰器1)+一份青椒(装饰器2)+一份火腿(装饰器3);双份牛肉青椒盖浇饭 = 一份白米饭(核心类)+ 一份青椒(装饰器4)+一份牛肉(装饰器5)+一份牛肉(装饰器5)。
至此,问题得到了圆满解决。接下来,我们对装饰器模式和继承模式进行对比总结。谷歌源码代码大全
下面进入代码实战环节,通过编程实现一个搭配食材的案例,展示装饰器模式的实现细节。
这个案例非常简单,我们需要在主食的基础上添加配菜,最终搭配出美味可口的食物套餐。其中主食包括米饭 rice 和面条 noodle 两条,配菜包括老干妈 LaoGanMa(老干妈拌饭顶呱呱)、火腿肠 HamSausage 和煎蛋 FriedEgg 三类。
事实上,如果需要,接码系统源码主食和配菜也可以随时进行扩展。在装饰器模式中,这种扩展行为的成本并不高。
接下来,展示一下总体的 UML 类图。
首先是对应于装饰器模式中核心类的是原始的主食 Food,我们声明了一个 interface,其中包含两个核心方法,Eat 和 Cost,含义分别为食用主食以及计算出主食对应的花费。
接下来是装饰器部分,我们声明了一个 Decorate interface,它们本身是在强依附于核心类(主食)的基础上产生的,只能起到锦上添花的作用,因此在构造器函数中,需要传入对应的主食 Food。
接下来分别声明三个装饰器的具体实现类,对应为老干妈 LaoGanMaDecorator、火腿肠 HamSausageDecorator 和煎蛋 FriedEggDecorator。
每个装饰器类的作用是对食物进行一轮装饰增强,因此需要在构造器函数中传入待装饰的食物,然后通过重写食物的 Eat 和 Cost 方法,实现对应的增强装饰效果。
下面提供另一种闭包实现装饰增强函数的实现示例,其实现也是遵循着装饰器模式的思路,但在形式上会更加简洁直观一些。
其中核心的处理方法 handleFunc 对应的是装饰器模式中的核心类,Decorate 增强方法对应的则是装饰器类,每次在执行 Decorate 的过程中,都会在 handleFunc 前后增加一些额外的附属逻辑。
为了加深理解,以下摘出一个实际项目中应用到装饰器模式的使用案例进行分析。
这里给到的案例是 grpc-go 中对拦截器链 chainUnaryInterceptors 的实现。
在 grpc-go 服务端模块中,每次接收到来自客户端的 grpc 请求,会根据请求的 path 映射到对应的 service 和 handler 进行执行逻辑的处理,但在真正调用 handler 之前,会先经历一轮对拦截器链 chainUnaryInterceptors 的遍历调用。
下面我们来观察一下其中具体的源码细节。
首先,对于拦截器类 UnaryServerInterceptor,本身是一个函数的类型。
下面是生成拦截器链的方法 chainUnaryInterceptors。该方法入参是用户定义好的一系列拦截器 interceptors,内部会按照顺序对拦截器进行组装,最终通过层层装饰增强的方式,将整个执行链路压缩成一个拦截器 UnaryServerInterceptor 的形式进行方法。
在这个过程中,就体现了我们今天讨论的装饰器模式的设计思路。核心业务处理方法 handler 对应的就是装饰器模式中的核心类,每一轮通过拦截器 UnaryServerInterceptor 对 handler 进行增强的过程,对应的就是一次“装饰”的步骤。
下面给出一个具体实现的装饰器的代码示例,可以看到其中在核心方法 handler 前后分别执行了对应的附属逻辑,起到了装饰的效果。
如果各位读友们想了解更多关于 grpc-go 的内容,可以阅读我之前发表的相关话题文章。
本期和大家交流了设计模式中的装饰器模式。装饰器模式能够动态地为对象增加某种特定的附属能力,相比于继承模式显得更加灵活,且符合开闭原则,可以作为继承模式的一种有效补充手段。