场景:用户能发布任务,每个任务有很多种服务(增值服务1,增值服务2,增值服务3 每个增值服务有对应的服务总份数,完成份数)。当任务结束时候用户可以在用户后台结算增值服务费用。管理员后台审核结算通过后将未完成的份数增值服务费用返还给用户
1.原来代码
用户后台:
public ActionResult Settlement(int Id)
{
//模拟数据库读取
TaskEntity task = new TaskEntity();
//增值服务1单份费用
var additionalOnePrice = 5M;
//增值服务费1结算费用
ViewBag.AdditionalOneFee = (task.AdditionalOneCount - task.AdditionalOneComplete) * additionalOnePrice;
//增值服务2单份费用
var additionalTwoPrice = 10M;
//增值服务费2结算费用
ViewBag.AdditionalTwoFee = (task.AdditionalTwoCount - task.AdditionalTwoComplete) * additionalTwoPrice;
//增值服务3单份费用
var additionalThreePrice = 1M;
//增值服务费1结算费用
ViewBag.AdditionalThreeFee = (task.AdditionalThreeCount - task.AdditionalThreeComplete) * additionalThreePrice;
return View();
}
视图上展示
ViewBag.AdditionalOneFee,
ViewBag.AdditionalTwoFee,
ViewBag.AdditionalThreeFee
场景1,在发布时间为2019-8-20号后的任务 增值服务2单份费用修改为3元
用户后台修改代码:
public ActionResult Settlement(int Id)
{
//模拟数据库读取
TaskEntity task = new TaskEntity();
//增值服务1单份费用
var additionalOnePrice = 5M;
//增值服务费1结算费用
ViewBag.AdditionalOneFee = (task.AdditionalOneCount - task.AdditionalOneComplete) * additionalOnePrice;
//增值服务2单份费用
var additionalTwoPrice = 10M;
//场景1:在发布时间为2019-8-20号后的任务 增值服务2单份费用修改为3元
if (task.CreateTime > DateTime.Parse("2019-06-20"))
additionalTwoPrice = 3M;
//增值服务费2结算费用
ViewBag.AdditionalTwoFee = (task.AdditionalTwoCount - task.AdditionalTwoComplete) * additionalTwoPrice;
//增值服务3单份费用
var additionalThreePrice = 1M;
//增值服务费1结算费用
ViewBag.AdditionalThreeFee = (task.AdditionalThreeCount - task.AdditionalThreeComplete) * additionalThreePrice;
return View();
}
用户后台添加判断
场景2,添加一个增值服务费4
用户后台:
public ActionResult Settlement(int Id)
{
//模拟数据库读取
TaskEntity task = new TaskEntity();
//增值服务1单份费用
var additionalOnePrice = 5M;
//增值服务费1结算费用
ViewBag.AdditionalOneFee = (task.AdditionalOneCount - task.AdditionalOneComplete) * additionalOnePrice;
//增值服务2单份费用
var additionalTwoPrice = 10M;
//场景1:在发布时间为2019-8-20号后的任务 增值服务2单份费用修改为3元
if (task.CreateTime > DateTime.Parse("2019-06-20"))
additionalTwoPrice = 3M;
//增值服务费2结算费用
ViewBag.AdditionalTwoFee = (task.AdditionalTwoCount - task.AdditionalTwoComplete) * additionalTwoPrice;
//增值服务3单份费用
var additionalThreePrice = 1M;
//增值服务费1结算费用
ViewBag.AdditionalThreeFee = (task.AdditionalThreeCount - task.AdditionalThreeComplete) * additionalThreePrice;
//场景2:添加一个增值服务费4
//增值服务4单份费用
var additionalFourPrice = 20M;
ViewBag.AdditionalFourFee = (task.AdditionalFourCount - task.AdditionalFourComplete) * additionalFourPrice;
return View();
}
用户后台添加增值服务4费用结算
视图上展示
ViewBag.AdditionalOneFee,
ViewBag.AdditionalTwoFee,
ViewBag.AdditionalThreeFee,
ViewBag.AdditionalFourFee
项目代码类似这样的情况,实现功能就行了不怎么符合面向对象的原则。每次需求方修改需求都要对应的模块大动干戈,一不小心复制粘贴的时候变量名称没有修改过来又是一个BUG。
痛定思痛狠下心来改写下。
抽象增值服务基类:
public abstract class AdditionalSevierBase
{
///
/// 构造函数
///
/// 单份增值服务费费用
protected AdditionalSevierBase(decimal AdditionalPrice)
{
this.additionalPrice = AdditionalPrice;
}
///
/// 单份增值服务费费用
///
protected decimal additionalPrice
{
get;
set;
}
///
/// 计算增值服务费
///
/// 任务信息
/// 增值服务费合集
public abstract void CalcFee(TaskEntity TaskInfo, Dictionary FeeDict);
}
再派生各个增值服务子类:
public sealed class AdditionalOneSevier : AdditionalSevierBase
{
///
/// 构造函数
///
/// 单份增值服务费费用
public AdditionalOneSevier(decimal AdditionalPrice)
: base(AdditionalPrice)
{
}
///
/// 计算增值服务费
///
/// 任务信息
/// 增值服务费合集
public override void CalcFee(TaskEntity TaskInfo, Dictionary FeeDict)
{
FeeDict.Add("AdditionalOneFee", (TaskInfo.AdditionalOneCount - TaskInfo.AdditionalOneComplete) * this.additionalPrice);
}
}
创建一个管理类用作调用以及依赖注入的容器:
public class AdditionalManage
{
public AdditionalManage()
{
//使用构造函数的方式依赖注入
additionlServierList = new List
{
new AdditionalOneSevier(5M),
new AdditionalTwoSevier(10M),
new AdditionalThreeSevier(1M),
};
}
///
/// 依赖注入的容器
///
private List< AdditionalSevierBase> additionlServierList;
///
/// 结算增值服务费
///
/// 任务实体
/// 哥哥增值服务费结算字典
public Dictionary Settlement(TaskEntity TaskInfo)
{
var feeDict = new Dictionary();
foreach (var item in additionlServierList)
{
item.CalcFee(TaskInfo, feeDict);
}
return feeDict;
}
}
用户后台修改为:
public ActionResult Settlement(int Id)
{
//模拟数据库读取
TaskEntity task = new TaskEntity();
AdditionalManage manage = new AdditionalManage();
ViewBag.AdditionalFeeDict= manage.Settlement(task);
return View();
}
视图上展示
ViewBag.AdditionalFeeDict["AdditionalOneFee"],
ViewBag.AdditionalFeeDict["AdditionalTwoFee"],
ViewBag.AdditionalFeeDict["AdditionalThreeFee"],
Note:因为这是DEMO不是正式的业务代码每个增值服务的计算逻辑有所不同,所以把各个增值服务单独封装成类而不是new多个类通过传参的方式结算增值服务费。
场景1,在发布时间为2019-8-20号后的任务 增值服务2单份费用修改为3元
派生一个新的增值服务类:
public sealed class AdditionalTwoUpdateSevier : AdditionalSevierBase
{
///
/// 构造函数
///
/// 单份增值服务费费用
public AdditionalTwoUpdateSevier(decimal AdditionalPrice)
: base(AdditionalPrice)
{
}
///
/// 计算增值服务费
///
/// 任务信息
/// 增值服务费合集
public override void CalcFee(TaskEntity TaskInfo, Dictionary FeeDict)
{
if (TaskInfo.CreateTime > DateTime.Parse("2019-06-20"))
{
FeeDict["AdditionalTwoFee"]= (TaskInfo.AdditionalTwoCount - TaskInfo.AdditionalTwoComplete) * this.additionalPrice;
}
}
}
在AdditionalManage类中注入一个新的派生类 AdditionalTwoUpdateSevier
这样控制器中的action完全不需要修改,同理添加新的增值服务费(场景2)也只要注入新的派生类
Note:通常像场景2这种情况有可能计算增值服务费中需要调用别的资源如接口,数据库等,会出现重复计算浪费开销的情况。可以修改新的派生类所有计算方式都写在 AdditionalTwoUpdateSevier 中,牵扯到依赖注入的另一个概念控制反转,将注入的控制权移交出去通过配置文件来控制注入哪些派生类