继续增加计算价格逻辑的复杂度...
业务需求:
增加商家功能,商品属于具体某一个商家,商家分等级,不同的等级对应不同的价格计算逻辑
商家等级分为新手、铜牌、银牌、金牌
新手:价格不变
铜牌:价格减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。