据我所知,几乎全部的互联网公司都带有和电商有关的项目,并且在大多数公司里面仍是举足轻重的重头戏,好比京东,淘宝。既然有电商项目,必然会涉及到商品,一旦有商品就会有各类促销活动,好比 满100减20,三八妇女节9折等等相似活动。做为一个coder怎么才能在实现产品狗的需求下,最小改动代码,最优雅的实现呢。今天菜菜不才,就D妹子的问题献丑一番。如下以.netCore c#代码为例,其余语言相似。c#
首先D妹子有一个商品的对象,商品里有一个价格的属性,价格的单位是分bash
class Product
{
//其余属性省略
public int Price { get; set; }
}
复制代码
下面有一个满100减20的活动,在结算价格的时候代码是这样的ide
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的缘由。ui
那具体要怎么优化呢?修改代码以前,我仍是想提醒一下,有几个要点须要注意一点:this
基于以上几点,首先把商品的对象作一下抽象spa
//商品抽象基类
abstract class BaseProduct
{
//商品价格,单位:分
public int Price { get; set; }
//获取商品价格抽象方法
public abstract int GetPrice();
}
//抽象商品(好比话费商品),继承商品基类
class VirtualProduct : BaseProduct
{
public override int GetPrice()
{
return this.Price;
}
}
复制代码
接下来活动的基类也须要抽象出来.net
//各类活动的抽象基类,继承要包装的类型基类
abstract class BaseActivity : BaseProduct
{
}
复制代码
有的同窗会问,这里为何要继承商品的基类呢?主要是为了活动的基类能嵌套使用,这样我就能够实现多个活动同时使用,若是不明白不要紧,带着这个问题接着往下看3d
实现一个打折的活动code
//打折活动基类,支持多个商品同时结算
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;
//满减的对应表
Dictionary<int, int> reductMap = null;
public ReductionActivity(Dictionary<int, 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() { Price=1000};
//打折活动
DiscountActivity da = new DiscountActivity(90, p);
var retPrice= da.GetPrice();
Console.WriteLine($"打折后的价格{retPrice}");
//还能叠加参加满减活动
Dictionary<int, int> m = new Dictionary<int, 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
复制代码
如今咱们终于能优雅一点的同时进行商品的满减和打折活动了
以上代码已经能够比较优雅的能进行单品的促销活动了,可是现实每每很骨感,真实的电商场景中多以多个商品结算为主,那用一样的思路怎么实现呢?
//商品列表的基类,用于活动结算使用
class ActivityListProduct : List<BaseProduct>
{
//商品列表活动结算的方法,基类必须重写
public virtual int GetPrice()
{
int ret = 0;
base.ForEach(s =>
{
ret += s.GetPrice();
});
return ret;
}
}
复制代码
//商品列表 活动的基类,继承自商品列表基类
internal abstract class BaseActivityList : ActivityListProduct
{
}
复制代码
//打折活动基类,支持多个商品同时结算
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;
//满减的对应表
Dictionary<int, int> reductMap = null;
public ReductionActivityList(Dictionary<int, 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()}");
//还能叠加参加满减活动
Dictionary<int, int> m = new Dictionary<int, 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妹子吗?
添加关注,查看更精美版本,收获更多精彩