纯粹的优化神经if-else
之前说写过一个 “注册表” 式优化,那种情况如下:
// —————*** 优化前 ***——————
// exportData 根据格式导出数据
func exportData(data interface{}, format string) error {
if format == "pdf" {
exportPDF(data)
} else if format == "csv" {
exportCSV(data)
} else if format == "json" {
exportJSON(data)
} else {
return errors.New("no exporter found for format: " + format)
}
return nil
}
// —————*** 优化后 ***——————
// exportData 根据格式导出数据
func exportData(data interface{}, format string) error {
exporter, exists := exporters[format] // 不同格式获得对应格式的闭包调用
if !exists {
return errors.New("no exporter found for format: " + format)
}
exporter(data) // 闭包调用传输数据获得想要结果
return nil
}
// exportPDF 导出为PDF格式
func exportPDF(data interface{}) {
fmt.Println("Exporting data as PDF...")
}
// exportCSV 导出为CSV格式
func exportCSV(data interface{}) {
fmt.Println("Exporting data as CSV...")
}
// exportJSON 导出为JSON格式
func exportJSON(data interface{}) {
fmt.Println("Exporting data as JSON...")
}这种你要硬说,也可以用 swich 去进行优化,毕竟本质上就是单一对象的不同情况区分。
但如果是多对象不同情况区分的话,就会实现的比较难受。特别还是下面这种策略模式昏厥的写法,一眼昏头:
func approveOrderEvilNested(o Order, u User) string {
if isEligibleAmount(o) {
if !o.HasDiscount {
if hasValidCurrency(o, u) {
for _, it := range o.Items {
if it.Price < 0 {
return "rejected"
}
}
return "approved"
} else {
return "rejected"
}
} else {
return "rejected"
}
} else {
return "rejected"
}
}下面是整个优化过程的源码:
package main
import (
"fmt"
)
/* ---------- 领域对象 ---------- */
type Item struct {
Price int
}
type Order struct {
Amount int
HasDiscount bool
Currency string
Items []Item
}
type User struct {
Region string
Currency string
}
type ValidCurrency struct {
UserRegion string
OrderCurrency string
}
/* ---------- 工具函数 ---------- */
func isEligibleAmount(o Order) bool {
return o.Amount >= 100
}
// 简单校验货币
func hasValidCurrency(o Order, u User) bool {
return o.Currency == u.Currency
}
// 助于优化区域检验,每次增加新情况只需要在这里增添就好了
var strictlyValidCurrencyMap = map[ValidCurrency]bool{
{UserRegion: "US", OrderCurrency: "USD"}: true,
{UserRegion: "EU", OrderCurrency: "EUR"}: true,
{UserRegion: "CN", OrderCurrency: "CNY"}: true,
}
// 严格区域校验货币
func hasStrictlyValidCurrency(o Order, u User) bool {
return strictlyValidCurrencyMap[ValidCurrency{u.Region, o.Currency}]
}
func rangeOrderItem(o Order) bool {
for _, it := range o.Items {
if it.Price < 0 {
return false
}
}
return true
}
/* ---------- 故意嵌套的“神经”写法 ---------- */
func approveOrderEvilNested(o Order, u User) string {
if isEligibleAmount(o) {
if !o.HasDiscount {
if hasValidCurrency(o, u) {
for _, it := range o.Items {
if it.Price < 0 {
return "rejected"
}
}
return "approved"
} else {
return "rejected"
}
} else {
return "rejected"
}
} else {
return "rejected"
}
}
/* ---------- 优化策略模式后,传统 if 写法 ---------- */
func approveOrderOptimize(o Order, u User) string {
if !isEligibleAmount(o) {
return "rejected"
}
if o.HasDiscount {
return "rejected"
}
if !hasValidCurrency(o, u) {
return "rejected"
}
for _, it := range o.Items {
if it.Price < 0 {
return "rejected"
}
}
return "approved"
}
/* ---------- 在传统优化上,实现合并写法:规则切片 ---------- */
func approveOrderFinalOptimize(o Order, u User) string {
rejectedRules := []func() bool{
func() bool { return o.HasDiscount },
func() bool { return !isEligibleAmount(o) },
func() bool { return !hasValidCurrency(o, u) },
func() bool { return !rangeOrderItem(o) },
}
for _, rule := range rejectedRules {
if rule() {
return "rejected"
}
}
return "approved"
}
/* ---------- 在传统基础上实现合并写法:规则切片,换成了严格区域校验 ---------- */
func approveOrderStrictlyFinalOptimize(o Order, u User) string {
rejectedRules := []func() bool{
func() bool { return !isEligibleAmount(o) },
func() bool { return o.HasDiscount },
func() bool { return !hasStrictlyValidCurrency(o, u) },
func() bool { return !rangeOrderItem(o) },
}
for _, rule := range rejectedRules {
if rule() {
return "rejected"
}
}
return "approved"
}
/* ---------- 测试 ---------- */
func main() {
// All is OK! 简单校验
// Order.Currency != User.Region 严格区域校验
good := Order{
Amount: 200,
HasDiscount: false,
Currency: "USD",
Items: []Item{
{50},
{60},
},
}
// Amount < 100,bad
bad1 := Order{
Amount: 50,
HasDiscount: false,
Currency: "USD",
Items: []Item{
{10},
},
}
// Order.Currency != User.Currency 简单校验
// Order.Currency == User.Region 严格区域校验
bad2 := Order{
Amount: 100,
HasDiscount: false,
Currency: "EUR",
Items: []Item{
{10},
},
}
u := User{
Region: "EU",
Currency: "USD",
}
// 测试
fmt.Println("simple evil nested :", approveOrderEvilNested(good, u), approveOrderEvilNested(bad1, u), approveOrderEvilNested(bad2, u))
fmt.Println("simple first optimize :", approveOrderOptimize(good, u), approveOrderOptimize(bad1, u), approveOrderOptimize(bad2, u))
fmt.Println("simple final optimize:", approveOrderFinalOptimize(good, u), approveOrderFinalOptimize(bad1, u), approveOrderFinalOptimize(bad2, u))
fmt.Println("strict final optimize:", approveOrderStrictlyFinalOptimize(good, u), approveOrderStrictlyFinalOptimize(bad1, u), approveOrderStrictlyFinalOptimize(bad2, u))
}测试输出为:
输出:
simple evil nested : approved rejected rejected
simple first optimize : approved rejected rejected
simple final optimize: approved rejected rejected
strictly final optimize: rejected rejected approved这里其实做了两个步骤:①优化原先策略模式,精简 if-else 基本逻辑判断代码。 ②使用函数式编程,将逻辑处理代码分离出 if-else 压缩处理结果上重复的代码量。
特别是第 ② 步,因为用了函数式编程,让相同为 rejected 为标准结果的代码块合并在一个模块内,这样后面如果 Order User 等对象因为业务要求新加了一些字段,多出一些新的校验需求,就可以直接在模块内(rejectedRules)内增添情况校验函数即可,而校验代码函数可以单独开一个模块进行函数处理逻辑编写,这样不仅仅让 if-else 内部的代码简洁,又让整个功能代码模块化。
RoLingG | 博客
评论(0)