Golang - 使用责任链模式代替IF ELSE
一、传统 IF 判断
1、在业务中使用大量的 if 判断
代码如下:
package main
type SellInfo struct {
Price float64
OrderCount int
TotalCount int
MemberShip int
}
func main2() {
var a = SellInfo{
Price: 1.0,
OrderCount: 1,
TotalCount: 20,
MemberShip: 1,
}
if a.Price > 0 {
println("true")
}
if a.TotalCount > a.OrderCount {
println("true")
}
if a.MemberShip == 1 {
println("true")
}
if a.Price < 100 && a.MemberShip == 2 {
println("true")
}
}
2、如果再继续添加新的条件?
在上面的代码中,如果业务又需要增加新的判断,继续添加if条件?这可能是无限if下去的无底洞?
if判断对cpu还是很消耗资源的(搜索:cpu对if分支判断),引入今天的主角:责任链。
责任链的思路:将一个复杂逻辑的流程进行分解,将每个判断条件的判断交给责任链节点进行处理,在处理完成后将结果传递给下一个节点。
二、责任链 KILL IF
1、正确使用接口与对象
代码如下:
package main
import "fmt"
type SomeConditions struct {
Price float64
OrderCount int
TotalCount int
MemberShip int
}
type Rule interface {
Check(s *SomeConditions) bool
}
type PriceCheck struct{}
func (p *PriceCheck) Check(s *SomeConditions) bool {
return s.Price > 0
}
这里定义了一个Rule的接口类型
接口: 在Go语言中接口(interface)是一种类型,一种抽象的类型
上面代码可以看到,有一个比较有意思的地方,就是使用了空结构体
type PriceCheck struct{}
然后在这个结构体上再追加一个实现接口的方法
func (p *PriceCheck) Check(s *SomeConditions) bool { }
2、go责任链核心代码
注意:这里需要判断业务的整体性,如果都是false,要求为true抛出返回,则需要更改如下代码
判断的整体业务是以true为基本,一旦发生false则抛出返回的原则
如下代码:
// 聚合所有条件
func chain(s *SomeConditions, rules ...Rule) bool {
for _, rule := range rules {
if !rule.Check(s) {
return false
}
}
return true
}
3、go责任链完整代码
以下实现了设计原则:
package main
import "fmt"
type SomeConditions struct {
Price float64
OrderCount int
TotalCount int
MemberShip int
}
type Rule interface {
Check(s *SomeConditions) bool
}
// 聚合所有条件
func chain(s *SomeConditions, rules ...Rule) bool {
for _, rule := range rules {
if !rule.Check(s) {
return false
}
}
return true
}
func main() {
SomeConditions := &SomeConditions{
Price: 1.00,
OrderCount: 2,
TotalCount: 10,
MemberShip: 2,
}
rules := []Rule{
&PriceCheck{},
&OrderCountCheck{},
&MemberShipCheck{},
&DiscountCheck{},
}
flag := chain(SomeConditions, rules...)
fmt.Println(flag)
}
type PriceCheck struct{}
func (p *PriceCheck) Check(s *SomeConditions) bool {
return s.Price > 0
}
type OrderCountCheck struct{}
func (o *OrderCountCheck) Check(s *SomeConditions) bool {
return s.TotalCount > s.OrderCount
}
type MemberShipCheck struct{}
func (m *MemberShipCheck) Check(s *SomeConditions) bool {
return s.MemberShip == 2
}
type DiscountCheck struct{}
func (d *DiscountCheck) Check(s *SomeConditions) bool {
return s.Price > 10 && s.MemberShip == 2
}