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

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

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

ExceptionHelper是自定义的异常处理帮助类,覆盖了个别异常的处理,如果是没有覆盖的异常,我们可能需要记录日志,并告诉客户出现了什么异常。相似地,Redeem方法也要做相同的处理,此处省略。

此时,我们已经实现了所有非功能需求:logging,防御性编程,事务,重试,和异常处理。将这些处理横切关注点的代码添加到原始的AccrueRedeem方法中使得它们膨胀成巨大的方法。现在代码可以去生产环境(或更可能去QA/预发布环境),但是这代码太糟糕了!

你可能在想这个描述有点过了,并不是所有的横切关注点都是必须的,是的,你可能大多数情况只需要一两个横切关注点,一些关注点可以移到数据层或UI层。但这里要说明的道理是横切关注点可以使你的代码变杂乱,使得代码更难阅读、维护和调试。

不使用AOP重构

是时候整理下代码了,因为AccrueRedeem方法中有很多重复代码,我们可以把这些代码放到它们自己的类或方法中。一种选择是将所有的非功能关注点重构到静态方法中,这是个馊主意,因为这会将业务逻辑紧耦合到非功能关注点代码中,虽然使方法看上去更短更可读了,但仍然留下了方法做的事情太多的问题。你也可以使用DI策略,将所有的logging,防御性编程和其他服务传给LoyaltyAccrualServiceLoyaltyRedemptionService的构造函数:

public class LoyalRedemptionServiceRefactored:ILoyaltyRedemptionService
{
    private readonly ILoyaltyDataService _loyaltyDataService;
    private readonly IExceptionHandler _exceptionHandler;//异常处理接口
    private readonly ITransactionManager _transactionManager;//事务管理者

    public LoyalRedemptionServiceRefactored(ILoyaltyDataService loyaltyDataService, IExceptionHandler exceptionHandler, 
        ITransactionManager transactionManager)
    {
        _loyaltyDataService = loyaltyDataService;
        _exceptionHandler = exceptionHandler;//通过依赖注入传入
        _transactionManager = transactionManager;
    }

    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);

        _exceptionHandler.Wrapper(() =>
        {
            _transactionManager.Wrapper(() =>
            {
                var pointsPerDay = 10;
                if (invoice.Vehicle.Size>=Size.Luxury)
                {
                    pointsPerDay = 15;
                }
                var totalPoints = numberOfDays*pointsPerDay;
                _loyaltyDataService.SubstractPoints(invoice.Customer.Id,totalPoints);
                invoice.Discount = numberOfDays*invoice.CostPerDay;
                // logging
                Console.WriteLine("Redeem complete: {0}",DateTime.Now);
            });
        });
    }
}

上面是重构过的版本,IExceptionHandler等的代码没有贴出来,请查看源码,这个版本比之前的好多了。我将异常处理代码和事务/重试代码分别放到了IExceptionHandlerITransactionManager中,这种设计有它的优势,一是它把那些代码段放到了他们自己的类中,以后可以重用;二是通过减少了横切关注点的噪音使得代码阅读更容易。

当然,Accrue方法也可以重构成这样,此处略过。重构之后,代码和最原始的状态差不多了。但是构造函数好像太庞大了,也就是依赖太多了,实际上,这里可以优化一下,往下看。

(编辑:徐州站长网)

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

热点阅读