北京建设局投诉网站首页,天河建设网站外包,福州设计网站,青岛网站建设公司点击上方蓝色字体#xff0c;关注我们菜菜哥#xff0c;YY说你帮她解决了几个问题#xff0c;也帮我解决一个呗原来是D妹子#xff0c;来坐我身边#xff0c;说下情况我的项目是个电商项目#xff0c;现在产品狗要给商品做活动正常呀我一个新手初来咋到顶不住压力了… 点击上方蓝色字体关注我们菜菜哥YY说你帮她解决了几个问题也帮我解决一个呗原来是D妹子来坐我身边说下情况我的项目是个电商项目现在产品狗要给商品做活动正常呀我一个新手初来咋到顶不住压力了上次来一个折扣活动现在又来一个满减正常呀最要命的两个活动还能叠加使用正常呀我写的代码让老大骂了一顿让我做优化代码有多烂离近一点我给你看看好嘞◆◆背景介绍◆◆ 据我所知几乎所有的互联网公司都带有和电商有关的项目而且在大多数公司里面还是举足轻重的重头戏比如京东淘宝。既然有电商项目必然会涉及到商品一旦有商品就会有各种促销活动比如 满100减20,三八妇女节9折等等类似活动。作为一个coder怎么才能在实现产品狗的需求下最小改动代码最优雅的实现呢。今天菜菜不才就D妹子的问题献丑一番。以下以.netCore c#代码为例其他语言类似。◆◆D妹子版本◆◆ 首先D妹子有一个商品的对象商品里有一个价格的属性价格的单位是分 class Product { //其他属性省略 public int Price { get; set; } }下面有一个满100减20的活动在结算价格的时候代码是这样的public int GetPrice() { Product p new Product(); int ret p.Price; if (p.Price 100*100) { ret ret - 20 * 100; } return ret; }有问题吗按照需求来说没有问题而且计算的结果也正确。但是从程序艺术来说其实很丑陋。现在又有一个全场9折的活动恰巧有一个商品参与了以上两个活动而且还可以叠加使用(假设活动参与的顺序是先折扣后满减)。这时候D妹子的代码就变成了这样 public int GetPrice() { Product p new Product(); //9折活动 int ret p.Price * 90 / 100; //满减活动 if (ret 100 * 100) { ret ret - 20 * 100; } return ret; }假如现在又来一个类似活动那这块代码还需要修改严重违反了开放关闭原则而且频繁修改已经上线的代码bug的几率会大大增高。这也是D妹子领导骂她并且让她codereview的原因。◆◆优化版本◆◆那具体要怎么优化呢修改代码之前我还是想提醒一下有几个要点需要注意一点1. 商品菜菜认为有一个共同的基类比较好这样就有了一个所有商品的控制点为以后统一添加属性留一个入口。好比一个网关系统为什么会诞生网关这个组件呢因为有了它我们能方便的统一添加认证授权统计等一些列行为。2. 任何促销的活动最好有一个基类作用类似商品基类。3. 对于商品而言任何促销活动是商品的行为变化点影响到的是最终的商品价格所以获取价格这个行为要做特殊的处理。4. 不同种类的促销活动应该能自行扩展不会影响别的类型促销活动。5. 不同种类的促销活动能叠加使用(其实这里涉及到每个活动计算的标准是商品原价还是促销之后价格的问题)。基于以上几点首先把商品的对象做一下抽象//商品抽象基类 abstract class BaseProduct { //商品价格单位分 public int Price { get; set; } //获取商品价格抽象方法 public abstract int GetPrice(); } //抽象商品比如话费商品继承商品基类 class VirtualProduct : BaseProduct { public override int GetPrice() { return this.Price; } }接下来活动的基类也需要抽象出来//各种活动的抽象基类继承要包装的类型基类 abstract class BaseActivity : BaseProduct { }有的同学会问这里为什么要继承商品的基类呢主要是为了活动的基类能嵌套使用这样我就可以实现多个活动同时使用如果不明白没关系带着这个问题接着往下看实现一个打折的活动//打折活动基类,支持多个商品同时结算 class DiscountActivity : BaseActivity { BaseProduct product null; public DiscountActivity(int discount, BaseProduct _product) { Discount discount; product _product; } //折扣比如 90折 即为90 public int Discount { get; set; } //获取折扣之后的价格 public override int GetPrice() { return product.GetPrice() * Discount / 100; } }实现一个满减的活动而且支持自定义满减条件 class ReductionActivity : BaseActivity { BaseProduct product null; //满减的对应表 Dictionaryint, int reductMap null; public ReductionActivity(Dictionaryint, int _redutMap, BaseProduct _product) { reductMap _redutMap; product _product; } //获取折扣之后的价格 public override int GetPrice() { var productAmount product.GetPrice(); //根据商品的总价获取到要减的价格 var reductValue reductMap.OrderByDescending(s s.Key).FirstOrDefault(s productAmount s.Key).Value; return productAmount - reductValue; } }现在我们来给商品做个促销活动吧 VirtualProduct p new VirtualProduct() { Price1000}; //打折活动 DiscountActivity da new DiscountActivity(90, p); var retPrice da.GetPrice(); Console.WriteLine($打折后的价格{retPrice}); //还能叠加参加满减活动 Dictionaryint, int m new Dictionaryint, int() ; m.Add(200, 5); //满200减5 m.Add(300, 10); m.Add(500, 20); m.Add(1000, 50); //这里活动能叠加使用了 ReductionActivity ra new ReductionActivity(m, da); retPrice ra.GetPrice(); Console.WriteLine($打折满减后的价格{retPrice}); ReductionActivity ra2 new ReductionActivity(m, ra); retPrice ra2.GetPrice(); Console.WriteLine($再打折后的价格{retPrice});输出结果打折后的价格900打折满减后的价格880再打折后的价格860现在我们终于能优雅一点的同时进行商品的满减和打折活动了◆◆进化到多个商品同时促销◆◆以上代码已经可以比较优雅的能进行单品的促销活动了但是现实往往很骨感真实的电商场景中多以多个商品结算为主那用同样的思路怎么实现呢1. 由于这次需要实现的是多商品促销结算所以需要一个自定义的商品列表来作为要进行结算的对象。此对象行为级别上与单品类似有一个需求变化点的抽象获取价格//商品列表的基类,用于活动结算使用 class ActivityListProduct : ListBaseProduct { //商品列表活动结算的方法基类必须重写 public virtual int GetPrice() { int ret 0; base.ForEach(s { ret s.GetPrice(); }); return ret; } }2. 把多商品促销活动的基类抽象出来供不同的促销活动继承使用,这里需要继承ActivityListProduct为什么呢和单品的类似为了多个子类能够嵌套调用//商品列表 活动的基类继承自商品列表基类 internal abstract class BaseActivityList : ActivityListProduct { }3. 创建一个打折和满减活动//打折活动基类,支持多个商品同时结算 class DiscountActivityList : BaseActivityList { ActivityListProduct product null; public DiscountActivityList(int discount, ActivityListProduct _product) { Discount discount; product _product; } //折扣比如 90折 即为90 public int Discount { get; set; } public override int GetPrice() { var productPrice product.GetPrice(); return productPrice * Discount / 100; } } //满减的活动 class ReductionActivityList : BaseActivityList { ActivityListProduct product null; //满减的对应表 Dictionaryint, int reductMap null; public ReductionActivityList(Dictionaryint, int _redutMap, ActivityListProduct _product) { reductMap _redutMap; product _product; } //获取折扣之后的价格 public override int GetPrice() { var productAmount product.GetPrice(); //根据商品的总价获取到要减的价格 var reductValue reductMap.OrderByDescending(s s.Key).FirstOrDefault(s productAmount s.Key).Value; return productAmount - reductValue; } }先来一波多商品促销活动VirtualProduct p new VirtualProduct() { Price 1000 }; VirtualProduct p2 new VirtualProduct() { Price 1000 }; ActivityListProduct lst new ActivityListProduct(); lst.Add(p); lst.Add(p2); DiscountActivityList dalist new DiscountActivityList(80, lst); Console.WriteLine($打折后的价格{dalist.GetPrice()}); DiscountActivityList dalist2 new DiscountActivityList(90, dalist); Console.WriteLine($打折后的价格{dalist2.GetPrice()}); DiscountActivityList dalist3 new DiscountActivityList(90, dalist2); Console.WriteLine($打折后的价格{dalist3.GetPrice()}); //还能叠加参加满减活动 Dictionaryint, int m new Dictionaryint, int(); m.Add(200, 5); //满200减5 m.Add(300, 10); m.Add(500, 20); m.Add(1000, 50); ReductionActivityList ral new ReductionActivityList(m, dalist3); Console.WriteLine($再满减打折后的价格{ral.GetPrice()});结算结果打折后的价格1600打折后的价格1440打折后的价格1296再满减打折后的价格1246现在基本上可以让D妹子不被挨骂了神化版本见留言区知道D妹子为什么取名D妹子吗为了答谢粉丝的支持菜菜二期福利来临你领取了吗●程序员过关斩将--你的面向接口编程一定对吗●程序员修神之路--高并发下为什么更喜欢进程内缓存●程序员修神之路--高并发优雅的做限流有福利●程序员过关斩将--快速迁移10亿级数据●程序员修神之路--分布式缓存的一条明路附代码●程序员修仙之路--把用户访问记录优化到极致互联网之路菜菜与君一同成长长按识别二维码关注你点的每个赞我都认真当成了喜欢