重构实践——为了try-catch大兴排场

可能是我们共同的强迫症,不要说看到,就算想到太多的try-catch也很难接受。

于是,开始了一些尝试,这些尝试都算是思维的锻炼、场面的见识、经验的积累。

Version1 —— 原始版本

一开始,在ConcreteService中,拥有了太多的try-catch,而影响码字的兴趣。

代码1 原始代码
/// <summary>
/// 契约
/// </summary>
public interface IUpdateManyManyThingContract
{
    bool UpdateSth1(DataSet ds);
    bool UpdateSth2(DataSet ds);
    bool UpdateSth3(DataSet ds);
    bool UpdateSth4(DataSet ds);
    //...
}

/// <summary>
/// 服务实现
/// </summary>
public class ConcreteService : IUpdateManyManyThingContract
{
    private IDao m_Dao;

    public bool UpdateSth1(DataSet ds)
    {
        try
        {
            var dt = ds.First();
            if (!dt.HasElements()) return true;

            foreach (DataRow row in dt.Rows)
            {
                //构造
                var entity = new Branch(row);
                m_Dao.SaveOrUpdate(entity);
            }
            return true;
        }
        catch (Exception ex)
        {
            Logger.Log(ex);
            return false;
        }
    }

    public bool UpdateSth2(DataSet ds)
    {
        try
        {
        }
        catch (Exception)
        {
        }
    }

    public bool UpdateSth3(DataSet ds)
    {
        throw new NotImplementedException();
    }

    public bool UpdateSth4(DataSet ds)
    {
        throw new NotImplementedException();
    }
    //many update methods,many try-catches...
}

如上代码,UpdateSth函数里面都需要实现一个try-catch,而觉得恶心到自己了。

Version2——(Extract Method)提取方法 + Func

于是,基于自己的积累,开始了重构的第一个版本。

针对这个服务(ConcreteService)的特殊性,定制了一个专门的方法进行控制——TrycatchBlock

代码2 提取方法片段
/// <summary>
/// 服务实现
/// </summary>
public class ConcreteService : IUpdateManyManyThingContract
{
    private IDao m_Dao;

    public bool UpdateSth1(DataSet ds)
    {
        return TrycatchBlock(() =>
        {
            var dt = ds.First();
            if (!dt.HasElements()) return true;

            foreach (DataRow row in dt.Rows)
            {
                //构造
                var entity = new Branch(row);
                m_Dao.SaveOrUpdate(entity);
            }
            return true;
        });
    }

    public bool UpdateSth2(DataSet ds)
    {
        return TrycatchBlock(() =>
        {
            //...
            return true;
            //...
            //return false;
        });
    }

    public bool UpdateSth3(DataSet ds)
    {
        throw new NotImplementedException();
    }

    public bool UpdateSth4(DataSet ds)
    {
        throw new NotImplementedException();
    }
    //many update methods,many try-catches...

    //try-catch控制块
    private bool TrycatchBlock(Func<bool> body)
    {
        try
        {
            return body();
        }
        catch (Exception ex)
        {
            Logger.Log(ex);
            return false;
        }
    }
}

是的,这是一次进步,将所有的try-catch的功能职责都集中到了一个函数里面,也方便调试了。

但是,还得每个方法都加上一句:return TrycatchBlock(() => { 。。。 })。

从本质上来说,还是在进行中重复。

Version3——过滤器思想(否决)

经过老大的指点:考虑MVC中的类似FilterAttribute的注解。

思路演进:MVC中,有一个HandErrorAttribute的特性,用于拦截控制器或者动作的异常。。。。。。对,这是个思路,但过了没多久,我就放弃了。

放弃理由:“Request请求——>路由数据——>ControllerInvoker——>反射调用Controller或Action。”,这里面用了很多元数据(***Descriptor,***Invoker等)手段,实现难度不小。

另外,我需要的是“instance.MethodAction”(对象直接调用方法)的方式,因为是为WCF直接提供服务(WCF会根据配置文件中服务的名称创建服务),不需要使用反射进行动态调用。

Version4——动态代理

浏览网页的过程中,想起动态代理——Castle Dynamic Proxy,是的,Moq,Spring.net等一系列优秀的框架中引用到了它。

V4.1.使用中间层

想起一个老外曾经说过的一句话“计算机的任何问题,都可以通过一个中间层来解决”,当然,这里的中间层,是一个广泛和抽象的概念,比如,中间1号调中间2号、中间2号调目标,可能是一个递归的结构也说不定。

于是使用interceptor继续一个版本:

代码3:中间层——ConcreteServiceProxy;拦截器——ServiceDynamicProxyInterceptor。
/// <summary>
/// 服务实现
/// </summary>
public class ConcreteService : IUpdateManyManyThingContract
{
    private IDao m_Dao;

    public bool UpdateSth1(DataSet ds)
    {
        var dt = ds.First();
        if (!dt.HasElements()) return true;

        foreach (DataRow row in dt.Rows)
        {
            //构造
            var entity = new Branch(row);
            m_Dao.SaveOrUpdate(entity);
        }
        return true;
    }

    public bool UpdateSth2(DataSet ds)
    {
        //...
        return true;
        //...
        //return false;
    }

    public bool UpdateSth3(DataSet ds)
    {
        throw new NotImplementedException();
    }

    public bool UpdateSth4(DataSet ds)
    {
        throw new NotImplementedException();
    }
    //many update methods,many try-catches...
}

public class ConcreteServiceProxy : IUpdateManyManyThingContract
{
    private ConcreteService m_Service;
    public ConcreteServiceProxy()
    {
        m_Service = ServiceDynamicProxyInterceptor.CreateServiceProxy<ConcreteService>();
    }
    public bool UpdateSth1(DataSet ds)
    {
        return m_Service.UpdateSth1(ds);
    }

    public bool UpdateSth2(DataSet ds)
    {
        return m_Service.UpdateSth2(ds);
    }

    public bool UpdateSth3(DataSet ds)
    {
        return m_Service.UpdateSth3(ds);
    }

    public bool UpdateSth4(DataSet ds)
    {
        return m_Service.UpdateSth4(ds);
    }
}

public class ServiceDynamicProxyInterceptor : IInterceptor
{
    /// <summary>
    /// 工厂方法
    /// </summary>
    /// <typeparam name="T">服务类型</typeparam>
    /// <returns>一个经过代理的服务</returns>
    public static T CreateServiceProxy<T>() where T : class
    {
        ProxyGenerator generator = new ProxyGenerator();
        ServiceDynamicProxyInterceptor interceptor = new ServiceDynamicProxyInterceptor();
        T entity = generator.CreateClassProxy<T>(interceptor);
        return entity;
    }

    public void Intercept(IInvocation invocation)
    {
        try
        {
            invocation.Proceed();
        }
        catch (Exception ex)
        {
            Log.Error(ex.Message);
            invocation.ReturnValue = false;
        }
    }
}

上述代码是一目了然,使用m_Service = ServiceDynamicProxyInterceptor.CreateServiceProxy<ConcreteService>();就得到一个代理过的对象,也就能够进行拦截

多了一个中间层——ConcreteServiceProxy,层次分明了,但是代码同样没有减少,这个似乎又看起来多次一举。

况且还要改配置文件,WCF的配置,如下下划线部分。

<service name="MyNameSpace.Service.ConcreteServiceProxy" behaviorConfiguration="WFServiceBehavior">

V4.2.IOC版

到使用中间层为止,我已经是能够接受的了。但老大觉得还可以再精简,确实是经验丰富,又被指点了,然后提点我使用IOC,目标是去除中间层——ConcreteServiceProxy。

思路:

1) 先使用动态代理创建一个被代理过的(Proxied)ConcreteService对象;

2) 将此对象放入IOC中(如Autofac,Unity等);

3) 如果需要使用ConcreteService类型的实例,从IOC中获取即可。

注:(去除了中间层——ConcreteServiceProxy;同时ConcreteService不用加try-catch;也不用改配置文件了)

代码4:去除了中间层——ConcreteServiceProxy;同时ConcreteService不用加try-catch;也不用改配置文件了

public class DependencyRegistrar : IDependencyRegistrar
{
    public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder)
    {
        var proxiedService = ServiceDynamicProxyInterceptor.CreateServiceProxy<ConcreteService>();
        builder.Register(c => proxiedServicec).As<ConcreteService>().InstancePerRequest();
    }

    public int Order
    {
        get { return 0; }
    }
}

一次多好的体验啊!!!

用DP(Dynamic Proxy)完成了拦截;用IOC完成了DI。

写到这里,问题来了,WCF能够通过配置文件配置的服务名称,即MyNameSpace.Service.ConcreteService,自动去IOC中找到被代理的对象吗?Autofac.WCF能不能帮助它完成呢?

(附)动态代理链接:

http://docs.castleproject.org/Tools.DynamicProxy.ashx

http://www.cnblogs.com/daxnet/archive/2011/09/07/2169520.html

http://www.cnblogs.com/RicCC/archive/2010/03/15/castle-dynamic-proxy.html

总结:就先写到这里,体验的感觉哪怕就是一点点,也很爽!欢迎拍砖。

重构实践——为了try-catch大兴排场

时间: 2024-11-13 09:05:32

重构实践——为了try-catch大兴排场的相关文章

微信Android模块化架构重构实践

微信Android架构历史 微信Android诞生之初,用的是常见的分层结构设计.这种架构简单.清晰并一直沿袭至今.这是微信架构的v1.x时代. 图1-架构演进 到了微信架构的v2.x时代,随着业务的快速发展,消息通知不及时和Android 2.3版本之前webview内存泄露问题开始突显.由于代码.内存.apk大小都在增长,对系统资源的占用越来越多,导致微信进程容易被系统回收.因此微信开始转向多进程架构,独立的通信进程保持长连接的稳定性,独立的webview进程也阻隔了内存泄露导致的问题. 时

转促销系统与交易系统的重构实践

如今大规模促销已经成为大大小小的电商平台及入驻商家运营的常态.随着业务的复杂化.运营的精细化,以及品类.平台.渠道的不断丰富,各种新的促销形式也层出不穷,贯穿从商品展示.搜索.购买.支付等整个流程,电商对于精细化.精准化促销运营的需求也越来越强烈. 一次促销活动几十万商品,一天之内几十个.上百个促销活动已是家常便饭,至于入驻商家的常态促销更是不胜枚举.双十一期间,电商平台和商家更是会使出浑身解数,火力全开,无品不促销. 促销规则支持分时段设置,多个活动能够叠加,促销系统中的数据量甚至会超过商品信

敏捷软件开发:原则、模式与实践——第5章 重构

第5章 重构 在Martin Fowler的名著<重构>一书中,他把重构定义为:“在不改变代码外在行为的前提下对对代码做出修改,以改进代码内部结构的过程.”可是我们为什么要改进已经能够工作的代码结构呢?我们不是都知道“如果它没有坏,就不要去修理它!”吗? 每一个软件模块都有3项职责.第一个职责是它运行起来所完成的功能.这也是该模块得以存在的原因.第二个职责是它要应对的变化.几乎所有的模块在它们的生命周期中都要变化,开发者有责任保证这种变化应尽可能地简单.一个难以改变的模块是有问题的,即使能够工

【DDD】业务建模实践 —— 发布帖子

本文是基于上一篇‘业务建模小招数’的实践,主要讲解‘发表帖子’场景的业务建模,包括:业务建模.业务模型.示例代码:示例代码会使用java编写,文末附有github地址.相比于<领域驱动设计>原书中的航运系统例子,社交服务系统的业务场景对于大家更加熟悉,相信更好理解.本文是[DDD]系列文章的第一篇,可参考:通过业务系统的重构实践DDD Round-I 业务建模 在大家的常识中,每个人都有自己的观点,并可以发表自己的观点,在社区中便表现为:发布帖子.那么谁发布帖子呢? 很明显是帖子作者,于是我们

【DDD】业务建模实践 —— 删除帖子

本文是基于上一篇‘业务建模战术’的实践,主要讲解‘删除帖子’场景的业务建模,包括:业务建模.业务模型.示例代码:示例代码会使用java编写,文末附有github地址.相比于<领域驱动设计>原书中的航运系统例子,社交服务系统的业务场景对于大家更加熟悉,相信更好理解.本文是[DDD]系列文章的第一篇,可参考:通过业务系统的重构实践DDD 业务建模 这里的‘删除帖子’场景是指帖子作者主动删除帖子,至于管理员通过后台管理端下线帖子,我们认为该行为不同于‘删帖’,需要单独处理. 我们来分析下“删除帖子”

【DDD】领域驱动设计实践 —— 业务建模小招数

本文结合团队在ECO(社区服务系统)业务建模过程中的实践经验,总结得到一些DDD业务建模的小招数,不一定是完美的,但是对我们团队来说很有效用,希望能帮到其他人.后面会陆续将项目中业务建模的一些经典例子放上来,分享给大家. ECO系统是线上旧系统,它的建模过程有别于新系统的业务建模.由于背着历史包袱,ECO的建模过程不是那么纯粹,很容易受到旧代码的影响,陷入代码的细节中,初期举步维艰,靠着小步快跑的方式得到了一些雏形和方法论,后面越来越顺,效果还是不错的. 本文为[DDD]系列文章中的其中一篇,其

重构的艺术 深入认识

重构是什么? 重构就是对软件内部结构的一种调整,目的是不改变软件可观察行为的前提下,提高可理解性,降低修改成本.不是为了提高性能,是为了提高可读性,可维护性. 重构,从某种角度讲,就是整理代码.整理归类. 程序员,要戴着两顶帽子,一个是添加新功能,一个是重构.对完成功能的代码进行整理. 重构的目的? 改进设计,使软件更容易理解.找出Bug,提高后期的编程速度.代码使逐渐的腐败的,腐烂的.经常的重构就是保证软件保质期的方法. 何时重构? 事不过三,三则重构. 添加新功能时重构. 修补错误时重构.

前端资源教程合集

综合类 前端知识体系 前端知识结构 Web前端开发大系概览 Web前端开发大系概览-中文版 Web Front-end Stack v2.2 En类资源汇总 免费的编程中文书籍索引 前端书籍 前端免费书籍大全 前端知识体系 免费的编程中文书籍索引 智能社 - 精通JavaScript开发 重新介绍 JavaScript(JS 教程) 麻省理工学院公开课:计算机科学及编程导论 JavaScript中的this陷阱的最全收集--没有之一 JS函数式编程指南 JavaScript Promise迷你书

前端网站资源精编!!

不要吝啬你的赞美喜欢就点个赞 目录: 1-------- 走进前端2-------- jQuery3-------- CSS4-------- Angularjs5-------- ES66-------- React7-------- 移动端API8-------- avalon9-------- Requriejs10-------- vue11-------- Seajs12-------- Less,sass13-------- Markdown14-------- D315------