GO面向对象(做CRUD专家)九 :增加计算价格逻辑的复杂度(二)

118 阅读2分钟

继续增加计算价格逻辑的复杂度...

业务需求:
增加商家功能,商品属于具体某一个商家,商家分等级,不同的等级对应不同的价格计算逻辑 商家等级分为新手、铜牌、银牌、金牌
新手:价格不变
铜牌:价格减1
银牌:价格减2
金牌:价格减3

代码如下:

const (
   ShopLevelNormal      = 0
   ShopLevelBronzeMedal = 10
   ShopLevelSilverMedal = 20
   ShopLevelGoldMedal   = 30
)

type Shop struct {
   ID    int
   Name  string
   Level int
}

type Item struct {
   ID          int
   Category    int
   Title       string
   Stock       int
   PriceMarket int
   Price       int
   PriceVIP    int
   Rebate      *int

   Instance interface{}

   Shop *Shop
}

func (bo *Item) priceCalculate() {
   // 断言计算价格
   if priceCalculator, ok := bo.Instance.(ItemPriceCalculator); ok {
      bo.Price = priceCalculator.Price()
   }

   // 根据店铺等级计算价格
   if bo.Shop.IsLevelBronzeMedal() {
      bo.Price -= 1
   } else if bo.Shop.IsLevelSilverMedal() {
      bo.Price -= 2
   } else if bo.Shop.IsLevelGoldMedal() {
      bo.Price -= 3
   }
}

先说一个代码小技巧,店铺等级用数字0、10、20、30分别代表普通、铜牌、银牌、金牌,当然也可以用0、1、2、3,这也是code review中经常见到的,0123会有什么问题,如果之后需求要在普通和铜牌等级中增加一个铁牌等级,就非常别扭,用0.5吗,现在是整数,要改变量类型还是改数据库字段类型,用4吗,第一,等级上不和谐,数字越大应该等级越高,另外有些需求需要判断大于某个等级(比如银牌)可以干什么,实现的时候就非常烦。

如果用10为步长,中间增加一个等级,例如0、10增加一个等级,可以为5,变成0、5、10,再在5、10之间增加一个等级变成5、7、10,如果冗余还不够,最开始可以加大步长,在以往的工作经验中,例如订单状态,十几种状态值,还经常会在状态之间增加新的状态,就可以把步长设置为20。

代码分析:
Item对象包含Shop对象,Item调用Shop属性Level计算商品价格,这里就有个“聚合对象”的概念,比如订单由用户User、商品Item、地址Address、物流信息Logistics多个对象组合成一个完整的Order对象,通常前端UI显示也要显示这些信息,举个例子,商品详情页面多数需要显示商家信息。

这里的聚合对象相当于DDD中的聚合根,聚合根是DDD的基石,可见其重要性,大家可以查阅资料,继续深入学习。

本文的聚合对象是通过手工对应的方式从仓存储查询出来,如果一个聚合对象涉及到很多子对象,会很麻烦,有没有更方便的方式,这就是下一篇文章我们要介绍的ORM。