• 重构实践——为了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

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

    Demo链接:http://files.cnblogs.com/pengzhen/TryCatchDemo.rar

  • 相关阅读:
    从命令行运行postman脚本
    Postman简单的接口测试
    请写出正则表达式(regex),取得下列黄色部分的字符串 TEL: 02-236-9655/9659 FAX:02-236-9654 (黄色部分即02-236-9655/9659 ) ( 测试面试题)
    okhttp 的使用
    GridView的簡單使用
    Fragment 中 ListView绑定ContextMenu
    charles的使用
    selenium元素定位(Java)
    App间相互跳转及图片分享
    微信模板消息的使用
  • 原文地址:https://www.cnblogs.com/pengzhen/p/3806650.html
Copyright © 2020-2023  润新知