原理
将多个处理器连成一个链条,处理器A处理请求成功后,将请求交给处理器B,处理器B处理成功后再交给处理器C,以此类推,链条上每个处理器各自承担自己的职责。如果处理器处理失败,那么不再继续往后传递处理。
实现方式
方式1
定义IDoHandler接口,业务处理类直接实现该接口实现业务方法,定义一个Handler类,该类持有IDoHandler、Successor,IDoHandler代表具体业务实现,Successor代表下一个Handler;HandlerChain用来表示处理器链条,从数据结构上来说是一个包含头尾指针的链表,链表中的元素就是Handler类
type IDoHandler interface {
DoHandle()
}
type Handler struct {
DoHandler IDoHandler
Successor *Handler
}
func (h *Handler) Handle() {
handled := true
h.DoHandler.DoHandle() //执行业务逻辑
if handled && h.Successor != nil {
h.Successor.Handle()
}
}
type HandlerChain struct {
Head *Handler
Tail *Handler
}
func (c *HandlerChain) AddHandler(handler *Handler) {
if c.Head == nil {
c.Head = handler
c.Tail = handler
} else {
c.Tail.Successor = handler
c.Tail = handler
}
}
func (c *HandlerChain) Handle() {
if c.Head != nil {
c.Head.Handle()
}
}
type ADoHandler struct{}
func (h *ADoHandler) DoHandle() {
println("A Handle")
}
type BDoHandler struct{}
func (h *BDoHandler) DoHandle() {
println("B Handle")
}
func ApplicationMain() {
chain := new(HandlerChain)
aHandler := new(Handler)
aHandler.DoHandler = new(ADoHandler)
bHandler := new(Handler)
bHandler.DoHandler = new(BDoHandler)
chain.AddHandler(aHandler)
chain.AddHandler(bHandler)
chain.Handle()
}
方式2
定义IHandler接口,HandlerChain持有一个IHandler的数组,依次调用数组中的每个子类Handler
type IHandler interface {
Handle() bool
}
type HandlerChainV2 struct {
handlerList []IHandler
}
func (c *HandlerChainV2) AddHandler(h IHandler) {
c.handlerList = append(c.handlerList, h)
}
func (c *HandlerChainV2) Handle() {
for i := range c.handlerList {
handled := c.handlerList[i].Handle()
if handled == false {
break
}
}
}
type AHandler struct{}
func (h *AHandler) Handle() bool {
println("A Handle")
}
type BHandler struct{}
func (h *BHandler) Handle() bool {
println("B Handle")
}
func ApplicationMain2() {
c := new(HandlerChainV2)
c.AddHandler(new(AHandler))
c.AddHandler(new(BHandler))
c.Handle()
}
变体实现
变体定义:不管处理器是否处理成功,都往后传递请求继续处理,不存在中途终止的情况
变体实现思路:实现1不管handled是否为true,只要successor不为nil就继续调用;实现2如果handler处理失败,那么也不需要break,继续往后执行
最佳实践
需求背景
对于支持 UGC(User Generated Content,用户生成内容)的应用(比如论坛)来说,用户生成的内容(比如,在论坛中发表的帖子)可能会包含一些敏感词(比如涉黄、广告、反动等词汇)。针对这个应用场景,我们就可以利用职责链模式来过滤这些敏感词。对于包含敏感词的内容,我们有两种处理方式,一种是直接禁止发布,另一种是给敏感词打马赛克(比如,用 *** 替换敏感词)之后再发布。
第一种处理方式符合 职责链模式的标准定义,第二种处理方式是职责链模式的变体。
第一种处理方式实现
type ISensitiveWordDoFilter interface {
DoFilter(words string) bool
}
type SensitiveWordFilter struct {
doFilter ISensitiveWordDoFilter
next *SensitiveWordFilter
}
func (f *SensitiveWordFilter) Filter(words string) bool {
handled := f.doFilter.DoFilter(words)
if handled && f.next != nil {
return f.next.Filter(words)
}
return handled
}
type SensitiveWordFilterChain struct {
head *SensitiveWordFilter
tail *SensitiveWordFilter
}
func (c *SensitiveWordFilterChain) AddFilter(filter *SensitiveWordFilter) {
if c.head == nil {
c.head = filter
c.tail = filter
} else {
c.tail.next = filter
c.tail = filter
}
}
func (c *SensitiveWordFilterChain) Filter(words string) bool {
if c.head != nil {
return c.head.Filter(words)
}
return true
}
type SexySensitiveWordDoFilter struct{}
func (f *SexySensitiveWordDoFilter) DoFilter(words string) bool {
if words == "sexy" {
return false
}
return true
}
type FuckSensitiveWordDoFilter struct{}
func (f *FuckSensitiveWordDoFilter) DoFilter(words string) bool {
if words == "fuck" {
return false
}
return true
}
func ApplicationMain3(words string) {
chain := new(SensitiveWordFilterChain)
sexyFilter := new(SensitiveWordFilter)
sexyFilter.doFilter = new(SexySensitiveWordDoFilter)
fuckFilter := new(SensitiveWordFilter)
fuckFilter.doFilter = new(FuckSensitiveWordDoFilter)
chain.AddFilter(sexyFilter)
chain.AddFilter(fuckFilter)
println(chain.Filter(words))
}
优点
-
应对代码复杂度
把大块逻辑拆成函数,把大类拆小类,是应对代码复杂度的有效手段。采用职责链模式,我们将不同Filter的敏感词过滤逻辑都给抽到了单独的类里面,SensitiveWordFilter类的代码就不会太多太复杂 -
满足开闭原则
当我们需要新增一个新的敏感词过滤逻辑时,只需要定义一个新的Filter即可,然后在客户端代码(使用职责链的代码)添加这个Filter即可,可以将整个代码分为框架部分(职责链部分)和客户端部分,新增Filter时框架部分不需要任何改动,满足开闭原则 -
可以灵活地选择需要的Filter