我的设计模式之旅、03 职责链模式

编程旅途是漫长遥远的,在不同时刻有不同的感悟,本文会一直更新下去。

程序介绍

本程序实现职责链模式,现有三批不同重量的货物,有三种工具可以托运,分别是自行车、汽车、卡车,未来工具可能会增多,判断这些货物由哪个工具运输。

PS C:\Users\小能喵喵喵\Desktop\设计模式\职责链模式> go run .
自行车拉货 5 kg
卡车拉货 500 kg
汽车拉货 200 kg

程序代码

chainOfResponsibility.go

package main

import "fmt"

type IHander interface {
	HandleRequest(weight float64)
	SetSuccessor(successor IHander)
}

type Handler struct {
	successor IHander
}

func (h *Handler) SetSuccessor(successor IHander) {
	h.successor = successor
}

type Truck struct {
	Handler
}

type Car struct {
	Handler
}

type Bike struct {
	Handler
}

func (t *Truck) HandleRequest(weight float64) {
	if weight <= 3000 {
		fmt.Printf("卡车拉货 %v kg\n", weight)
	} else {
		if t.successor != nil {
			t.successor.HandleRequest(weight)
		}
	}
}

func (c *Car) HandleRequest(weight float64) {
	if weight <= 200 {
		fmt.Printf("汽车拉货 %v kg\n", weight)
	} else {
		if c.successor != nil {
			c.successor.HandleRequest(weight)
		}
	}
}

func (b *Bike) HandleRequest(weight float64) {
	if weight <= 10 {
		fmt.Printf("自行车拉货 %v kg\n", weight)
	} else {
		if b.successor != nil {
			b.successor.HandleRequest(weight)
		}
	}
}

handler结构体是所有工具的基类,抽象出了共同的属性和设置后继者行为。

Handler接口实现鸭子类型,用于确保具体处理者有效,必须实现两种必要的方法,客户端通过声明Handler接口去实例化具体处理者(里氏代换原则),当处理者添加,比如飞机空运,不会影响到客户端代码模块。

main.go

package main

func main() {
	var truck IHander = &Truck{}
	var car IHander = &Car{}
	var bike IHander = &Bike{}
	bike.SetSuccessor(car)
	car.SetSuccessor(truck)
	// 第一批货
	bike.HandleRequest(5)
	// 第二批货
	bike.HandleRequest(500)
	// 第三批货
	bike.HandleRequest(200)
}

Console

PS C:\Users\小能喵喵喵\Desktop\设计模式\职责链模式> go run .
自行车拉货 5 kg
卡车拉货 500 kg
汽车拉货 200 kg

思考总结

什么是职责链模式

image-20220909113450487

职责链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,知道有一个对象处理它为止。这种类型的设计模式属于行为型模式。

如果没有职责链模式,当处理者增多或修改时,会违背开放-封闭原则,不容易维护,不灵活。类有太多责任,导致不够灵活。可以利用多态性、职责链模式化解分支带来的僵化。

//管理者类处理请求伪代码
switch 请求{
	条件1 : 
		   方法A处理(请求)
	条件2 : 
		   方法B处理(请求)
	条件3 : 
		   方法C处理(请求)
}

意图:责任链模式为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦(发出请求的客户端并不知道哪一个对象最终会处理这个请求,它只管发请求,这样可以再不影响客户端的情况下动态组织请求处理者,重新分配责任)。通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。每个处理者仅需保持一个指向其后继者的引用,而不需保持它所有的候选者的引用,大大降低耦合度。

主要解决:职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。

如何解决:拦截的类都实现统一接口。

关键代码:Handler 里面聚合它自己,在 HandlerRequest 里判断是否合适,如果没达到条件则向下传递,向谁传递之前 set 进去。

应用实例: 1、红楼梦中的"击鼓传花"。 2、JS 中的事件冒泡。

优点:

  • 降低耦合度。它将请求的发送者和接收者解耦。
  • 简化了对象。使得对象不需要知道链的结构。
  • 增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
  • 增加新的请求处理类很方便。

缺点:

  • 不能保证请求一定被接收。一个请求极有可能到了链的末端都得不到处理,或者因为没有正确配置而得不到处理。
  • 系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。
  • 可能不容易观察运行时的特征,有碍于除错。

使用场景:

  • 有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。
  • 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
  • 可动态指定一组对象处理请求。

参考资料

  • 《Go语言核心编程》李文塔
  • 《Go语言高级编程》柴树彬、曹春辉
  • 《大话设计模式》程杰
  • 单例模式 | 菜鸟教程
posted @ 2022-09-09 11:56  小能日记  阅读(18)  评论(0编辑  收藏  举报