加入收藏 | 设为首页 | 会员中心 | 我要投稿 江门站长网 (https://www.0750zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 运营中心 > 网站设计 > 教程 > 正文

.Net中的AOP系列之构建一个汽车租赁应用

发布时间:2016-10-29 02:51:54 所属栏目:教程 来源:站长网
导读:副标题#e# 返回《.Net中的AOP》系列学习总目录 本篇目录 开始一个新项目 没有AOP的生活 变更的代价 使用AOP重构 本系列的源码本人已托管于Coding上:点击查看。 本系列的实验环境:VS 2013 Update 5(建议最好使用集成了Nuget的VS版本,VS Express版也够用
副标题[/!--empirenews.page--]

返回《.Net中的AOP》系列学习总目录


本篇目录
  • 开始一个新项目
  • 没有AOP的生活
  • 变更的代价
  • 使用AOP重构

本系列的源码本人已托管于Coding上:点击查看。

本系列的实验环境:VS 2013 Update 5(建议最好使用集成了Nuget的VS版本,VS Express版也够用),安装了PostSharp。

这篇博客覆盖的内容包括:

  • 为项目创建需求
  • 从零编写代码来满足需求
  • 不使用AOP重构凌乱的代码
  • 使用AOP来重构代码

这一节会构建一个汽车租赁系统,先是给定业务需求,然后逐渐地添加代码来满足那些需求。
一开始不使用任何AOP,从零开始敲代码。业务需求是最重要的,因此我们先做需求,一旦满足了业务逻辑,然后再覆盖非功能需求。最后,尽可能地简化并重构代码,不使用AOP来重构横切关注点。
这些都完成之后,就会转向一个应用生命周期的长尾阶段。软件很少是长期不变的:新的功能需求和新发现的bugs。很少有软件的开发阶段会比生产阶段长,这就意味着大多数软件的生命周期是维护阶段。一个维护困难或昂贵的应用会导致高代价或者低品质(或两者都有),最终形成一个大泥球。
然后,会使用PostSharp重构代码,将各自的横切关注点分离到它们自己的类中。一旦重构完成,你就会看到使用AOP的好处,特别是添加更多功能时。

开始一个新项目

时间:现在
地点:你公司(汽车租赁服务相关)的研发部的办公室
人物:你的技术团队或者只有你自己
背景:启动一个新的项目,高大上一点,叫做客户忠诚度系统,low一点,叫做客户积分程序。目的是为了增加销售,奖励那些经常购买服务的客户。比如,客户今天租赁了一辆车,那么他就会获得积分,积分累积多了之后,以后可以用于抵消一部分租赁费用或其他费用。

假设有一个基本的三层架构,如下图。我们会从应用到这个积分系统的核心业务逻辑层着手编写代码,持久化层会跟踪客户的忠诚度积分,业务逻辑层供所有的UI层使用:网站,APP和店员使用的桌面端。

这一篇,我们主要看一下中间一层的业务逻辑层。我们可以假设持久化层已经实现了,还要假设一旦业务逻辑实现了,UI也就实现了。

业务需求

项目经理和利益相关人(比如销售和市场)确定了下图的业务需求,你已经确定了两个主要的需求集:累积积分和使用累积的积分 兑换奖励。

现在的业务需求就是:客户每租一天普通型车辆,累积一积分,豪华型或者大型车辆,每天两积分。这些积分会在他们支付之后并返还了车以后会增加到他们的账户中。一旦客户累积了10积分,那么就可以使用这些积分兑换奖励了,具体兑换规则见上图。
这就是所有业务规则,但是在实现之前还是得和销售和市场确定好:因为他们将来肯定还会更改或者添加一些东西。

必要的非功能需求

在给项目经理估算时间和花销之前,你有自己必须要解决的技术关注点。
第一,需要记录日志。如果客户的积分累积得不对(累积少了),那么他们会生气的,因此必须确保记录了业务逻辑处理的一切(尤其是起初阶段)。
第二,因为业务逻辑代码会被多个UI应用使用,要确保传入业务层的数据是合法的,你的队友可能会在UI里写入一些集成代码,因此,必须编写防御性代码来检查无意义的边缘情况和参数。
第三,还是因为业务逻辑代码会被多个UI应用使用,这些UI可能会使用不同类型的连接(缓慢的移动手机的连接,国外浏览器访问等等),你需要采用事务和重试逻辑来确保维护数据集成以及给用户提供一个愉快的体验。
最后,总有意外会发生,你可能不知道此时你会使用何种类型的持久化,所以需要某种方法处理异常(很可能是记录日志)。

没有AOP的生活

将评估提交给项目经理之后,所有的批准和文件也已经签署了,现在就可以开始了。

新建一个解决方案,名叫CarRental,并创建一个类库项目存放业务逻辑,取名CarRental.Core

编写业务逻辑

创建一个累积积分的接口,代码如下:

public interface ILoyaltyAccrualService
{
    void Accrue(RentalAgreement agreement);
}

RentalAgreement是该积分系统领域公用的一个实体类,因此按理说它应该在一个不同的程序集,但这里为了演示,我创建了一个Entities的文件夹,存放所有的实体。


public class RentalAgreement
{
    public Guid Id { get; set; }
    public Customer Customer { get; set; }
    public Vehicle Vehicle { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
}


 public class Customer
 {
     public Guid Id { get; set; }
     public string Name { get; set; }
     public string DriversLicense { get; set; }
     public DateTime DateOfBirth { get; set; }
 }

 public class Vehicle
 {
     public Guid Id { get; set; }
     public string Make { get; set; }
     public string Model { get; set; }
     public Size Size { get; set; }
     public string Vin { get; set; }
 }

 public enum Size
 {
     Compact=0,
     Midsize,
     FullSize,
     Luxury,
     Truck,
     SUV
 }

再回头看ILoyaltyAccrualService接口,该接口有一个使用了这些实体的Accure方法,用来为客户累积积分。下面是该接口的实现,它会依赖一个持久化数据的服务。Accure方法会包含了计算协议中天数和这些天共累积多少积分的业务逻辑,并将这些积分数量存储到数据库中。

public class LoyaltyAccrualService:ILoyaltyAccrualService
{
    private readonly ILoyaltyDataService _loyaltyDataService;

    public LoyaltyAccrualService(ILoyaltyDataService loyaltyDataService)
    {
        _loyaltyDataService = loyaltyDataService;//数据服务必须在该对象初始化时传入该对象
    }
    /// <summary>
    /// 该方法包含了积分系统累积客户积分的逻辑和规则
    /// </summary>
    /// <param name="agreement">租赁协议实体</param>
    public void Accrue(RentalAgreement agreement)
    {
        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);
    }
}

(编辑:江门站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读