链模式( Chain Pattern)是用于编写更好、更健壮的代码的众多设计模式之一。
这种模式的工作原理类似于链式生产,链中的每个环节都负责一项具体任务。当链启动时,第一个执行其任务,然后,如果没有错误,则传递到下一个,直到最后一个负责人。到那时,链条就结束了。
golang 不是 OOP 语言,因此为了模拟它,它必须使用接口和基本结构。
package chain
type Chain[T any] interface { Perform(T) error }
type Responsible[T any] interface { Next(T) error Apply(T) error }
type BaseResponsible[T any] struct { next Responsible[T] }
func (r *BaseResponsible[T]) Next(i T) error { if r.next == nil { return nil } if err := r.next.Apply(i); err != nil { return err }
return r.next.Next(i) }
func (r *BaseResponsible[T]) SetNext(n Responsible[T]) { r.next = n }
|
上面的代码显示了两个重要的接口:链和责任(Chain & Responsible 职责链)。
- Chain 为执行责任链提供了一个容器。因此,它的职责是触发第一个责任链。
- Responsible职责、责任 为链中的责任链接提供 "执行和下一步"。apply 方法将执行负责人的任务。next 方法将调用(传递)下一个责任链。BaseResponsible 结构与 Responsible 接口相结合,提供了一个抽象类。其中,next 方法的实现使 apply 方法成为一个抽象方法(有待实现)。
职责实现代码
package responsibles
type Triangle struct { A int B int C float64 }
type basePythagoreanTheorem struct { chain.BaseResponsible[*Triangle] }
type ASideResponsible struct { basePythagoreanTheorem }
func (r *ASideResponsible) Apply(t *Triangle) error { t.A = rand.Intn(100) return nil }
type BSideResponsible struct { basePythagoreanTheorem }
func (r *BSideResponsible) Apply(t *Triangle) error { t.B = rand.Intn(100) return nil }
type CSideResponsible struct { basePythagoreanTheorem }
func (r *CSideResponsible) Apply(t *Triangle) error { t.C = math.Sqrt(float64(t.A*t.A + t.B*t.B)) return nil }
type PythagoreanTheoremChain struct { start Responsible[*Triangle] }
func (p PythagoreanTheoremChain) Perform(t *Triangle) error { if err := p.start.Apply(t); err != nil { return err } return p.start.Next(t) }
func NewPythagoreanTheoremChain() chain.Chain[*Triangle] { c := &CSideResponsible{}
b := &BSideResponsible{} b.SetNext(c) a := &ASideResponsible{} a.SetNext(b)
return &PythagoreanTheoremChain{start: a} }
|
上述实现将根据勾股定理创建一个三角形。随机选择 A 边和 B 边,然后根据定理计算 C 边(斜边)。其他方法
当然,也可以采用其他方法,如传递链(前一个的输出是后一个的输入)或完全独立负责。
此外,在前面的示例中,我们只是超级傻瓜式地使用了这种模式,但它还可以用于更多、更大的用途。例如,数据收集。
数据收集工作可能会一团糟,要从许多外部服务(REST、DB、SOAP 等)中请求数据,还要执行对内部/外部进行某种更改的任务,这可不是一件容易的事。
在这种情况下,这种模式大放异彩。这是因为它允许将步骤分离成完全隔离的负责步骤(它们之间可以有自己的日志记录器、客户端、配置等)(正如 SOLID 所喜欢的那样),并且链的过程是有顺序的,因此可以根据 "在执行此任务之前必须使用哪些数据 "来设计链。