虽然审计积分事务还不是一个需求,但是为了安全起见,最好还是记录每个请求,至少是为了QA(质量保证)的目的。在生产环境,可能会限制或减少日志,但是现在我们要放一些简单的日志帮助开发者重现QA找到的bugs。
现在,当累积积分和兑换积分时,添加日志,其余代码和之前的一样。
/// <summary>
/// 该方法包含了积分系统累积客户积分的逻辑和规则
/// </summary>
/// <param name="agreement">租赁协议实体</param>
public void Accrue(RentalAgreement agreement)
{
Console.WriteLine("Accrue:{0}",DateTime.Now);
Console.WriteLine("Customer:{0}",agreement.Customer.Id);
Console.WriteLine("Vehicle:{0}",agreement.Vehicle.Id);
var rentalTimeSpan = agreement.EndDate.Subtract(agreement.StartDate);
var numberOfDays = (int)rentalTimeSpan.TotalDays;
var pointsPerDay = 1;
if (agreement.Vehicle.Size >=Size.Luxury)
{
pointsPerDay = 2;
}
var points = numberOfDays*pointsPerDay;
//调用数据服务存储客户获得的积分
_loyaltyDataService.AddPoints(agreement.Customer.Id,points);
Console.WriteLine("Accrue Complete:{0}",DateTime.Now);
}
public void Redeem(Invoice invoice, int numberOfDays)
{
Console.WriteLine("Redeem:{0}",DateTime.Now);
Console.WriteLine("Invoice:{0}",invoice.Id);
var pointsPerDay = 10;
if (invoice.Vehicle.Size>=Size.Luxury)
{
pointsPerDay = 15;
}
var totalPoints = pointsPerDay*numberOfDays;
invoice.Discount = numberOfDays*invoice.CostPerDay;
_loyaltyDataService.SubstractPoints(invoice.Customer.Id,totalPoints);
Console.WriteLine("Redeem Complete:{0}",DateTime.Now);
}
现在还不是很糟糕,只不过在每个实现中添加了几行代码而已。咱们继续往下走!
防御性编程
因为我们的业务逻辑没有对传入的参数进行控制,因此必须要检查一下是否是最坏的情景。比如,如果Accrue 方法传入一个null会怎样?我们的业务逻辑不能处理这个,所以会抛异常,但我们希望它能调用我们的API处理这个异常,如果处理不了,就提醒UI开发者或QA发生了一些错误的东西。这种哲学就叫防御性编程,只是为了减少危险场景的风险。
下面我们使用防御性编程检查传入参数为null的无效场景:
public void Accrue(RentalAgreement agreement)
{
//防御性编程
if (agreement==null)
{
throw new Exception("agreement为null!");
}
//日志
Console.WriteLine("Accrue:{0}",DateTime.Now);
Console.WriteLine("Customer:{0}",agreement.Customer.Id);
Console.WriteLine("Vehicle:{0}",agreement.Vehicle.Id);
var rentalTimeSpan = agreement.EndDate.Subtract(agreement.StartDate);
var numberOfDays = (int)rentalTimeSpan.TotalDays;
var pointsPerDay = 1;
if (agreement.Vehicle.Size >=Size.Luxury)
{
pointsPerDay = 2;
}
var points = numberOfDays*pointsPerDay;
//调用数据服务存储客户获得的积分
_loyaltyDataService.AddPoints(agreement.Customer.Id,points);
Console.WriteLine("Accrue Complete:{0}",DateTime.Now);
}
我们也可以检查RentalAgreement 的属性,但现在上面的就足够了。Redeem 的实现也有相同的问题,numberOfDays 参数的值不能小于1,Invoice 参数也不能为null,因此也必须使用防御性编程:
public void Redeem(Invoice invoice, int numberOfDays)
{
//防御性编程
if (invoice==null)
{
throw new Exception("invoice为null!");
}
if (numberOfDays<=0)
{
throw new Exception("numberOfDays不能小于1!");
}
//logging
Console.WriteLine("Redeem:{0}",DateTime.Now);
Console.WriteLine("Invoice:{0}",invoice.Id);
var pointsPerDay = 10;
if (invoice.Vehicle.Size>=Size.Luxury)
{
pointsPerDay = 15;
}
var totalPoints = pointsPerDay*numberOfDays;
invoice.Discount = numberOfDays*invoice.CostPerDay;
_loyaltyDataService.SubstractPoints(invoice.Customer.Id,totalPoints);
Console.WriteLine("Redeem Complete:{0}",DateTime.Now);
}
现在我们的代码开始变得具有防御性了,如果在核心逻辑的控制之外发生了错误,也不会影响到我们了。
在添加了日志和防御性代码之后,Accrue 和Redeem 方法开始变得有点长了,也有点重复,但继续看一下事务和重试逻辑。
使用事务和重试 (编辑:成都站长网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|