作者:书友23295799 | 来源:互联网 | 2023-09-11 17:03
一个菜鸟的设计模式之旅,文章可能会有不对的地方,恳请大佬指出错误。编程旅途是漫长遥远的,在不同时刻有不同的感悟,本文会一直更新下去。程序介绍本程序实现职责链模式,现有三批不同重
一个菜鸟的设计模式之旅,文章可能会有不对的地方,恳请大佬指出错误。
编程旅途是漫长遥远的,在不同时刻有不同的感悟,本文会一直更新下去。
程序介绍
本程序实现职责链模式,现有三批不同重量的货物,有三种工具可以托运,分别是自行车、汽车、卡车,未来工具可能会增多,判断这些货物由哪个工具运输。
PS C:\Users\小能喵喵喵\Desktop\设计模式\职责链模式> go run .
自行车拉货 5 kg
卡车拉货 500 kg
汽车拉货 200 kg
程序代码
chainOfResponsibility.go
package main
import "fmt"
type Handler interface {
HandleRequest(weight float64)
SetSuccessor(successor Handler)
}
type handler struct {
successor Handler
}
func (h *handler) SetSuccessor(successor Handler) {
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 Handler = &Truck{}
var car Handler = &Car{}
var bike Handler = &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
思考总结
什么是职责链模式
职责链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,知道有一个对象处理它为止。这种类型的设计模式属于行为型模式。
如果没有职责链模式,当处理者增多或修改时,会违背开放-封闭原则
,不容易维护,不灵活。类有太多责任,导致不够灵活。可以利用多态性、职责链模式化解分支带来的僵化。
//管理者类处理请求伪代码
switch 请求{
条件1 :
方法A处理(请求)
条件2 :
方法B处理(请求)
条件3 :
方法C处理(请求)
}
意图:责任链模式为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦(发出请求的客户端并不知道哪一个对象最终会处理这个请求,它只管发请求,这样可以再不影响客户端的情况下动态组织请求处理者,重新分配责任)。通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。每个处理者仅需保持一个指向其后继者的引用,而不需保持它所有的候选者的引用,大大降低耦合度。
主要解决:职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。
如何解决:拦截的类都实现统一接口。
关键代码:Handler 里面聚合它自己,在 HandlerRequest 里判断是否合适,如果没达到条件则向下传递,向谁传递之前 set 进去。
应用实例: 1、红楼梦中的"击鼓传花"。 2、JS 中的事件冒泡。
优点:
- 降低耦合度。它将请求的发送者和接收者解耦。
- 简化了对象。使得对象不需要知道链的结构。
- 增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
- 增加新的请求处理类很方便。
缺点:
- 不能保证请求一定被接收。一个请求极有可能到了链的末端都得不到处理,或者因为没有正确配置而得不到处理。
- 系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。
- 可能不容易观察运行时的特征,有碍于除错。
使用场景:
- 有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。
- 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
- 可动态指定一组对象处理请求。
参考资料
- 《Go语言核心编程》李文塔
- 《Go语言高级编程》柴树彬、曹春辉
- 《大话设计模式》程杰
- 单例模式 | 菜鸟教程