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

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

Version1 —— 原始版本

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

代码 原始代码
/// <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。

代码 提取方法片段
/// <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 ; }
}
}

一次多好的体验啊!!!

用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

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

  1. 网易新闻App架构重构实践:DDD正走向流行

    网易新闻App架构重构实践:DDD正走向流行 https://mp.weixin.qq.com/s/FdwrT_xn3CQqpWoRVBttvQ 小智 InfoQ 2020-05-14 作者 | 小智 ...

  2. 通过业务系统的重构实践DDD

    最近新接了一个业务系统——社区服务系统,为了快速熟悉和梳理老系统的业务逻辑和代码,同时对老系统代码做一些优化,于是打算花上一个月时间不间断地对老系统服务进行重构.同时,考虑到社区业务的复杂性,想起了之 ...

  3. 高德渲染网关Go语言重构实践

    ​1.导读 高德启动Go业务建设已经有段时间了,主要包含Go应用落地,Go中间件建设,云原生三个部分.经过持续的发力,在这些方面取得了不错的进展.高德Go业务落地过程是如何实现的,遇到过哪些问题,如何 ...

  4. Web前端开发最佳实践(2):前端代码重构

    前言 代码重构是业内经常讨论的一个热门话题,重构指的是在不改变代码外部行为的情况下进行源代码修改,所以重构之前需要考虑的是重构后如何才能保证外部行为不改变.对于后端代码来说,可以通过大量的自动化测试来 ...

  5. Vue 项目架构设计与工程化实践

    来源 文中会讲述我从0~1搭建一个前后端分离的vue项目详细过程 Feature: 一套很实用的架构设计 通过 cli 工具生成新项目 通过 cli 工具初始化配置文件 编译源码与自动上传CDN Mo ...

  6. 【DDD】领域驱动设计实践 —— 框架实现

    本文主要了在社区服务系统(ECO)中基于SpringMVC+mybatis框架对DDD的落地实现.本文为系列文章中的其中一篇,其他内容可参考:通过业务系统的重构实践DDD. 框架实现图 该框架实现基本 ...

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

    本文结合团队在ECO(社区服务系统)业务建模过程中的实践经验,总结得到一些DDD业务建模的小招数,不一定是完美的,但是对我们团队来说很有效用,希望能帮到其他人.后面会陆续将项目中业务建模的一些经典例子 ...

  8. 20155314 2016-2017-2 《Java程序设计》实验三 敏捷开发与XP实践

    20155314 2016-2017-2 <Java程序设计>实验三 敏捷开发与XP实践 实验内容 XP基础 XP核心实践 相关工具 实验知识点总结 (一)敏捷开发与XP 软件工程:把系统 ...

  9. 美团外卖Android平台化的复用实践

    美团外卖平台化复用主要是指多端代码复用,正如美团外卖iOS多端复用的推动.支撑与思考文章所述,多端包含有两层意思:其一是相同业务的多入口,指美团外卖业务需要在美团外卖App(下文简称外卖App)和美团 ...

随机推荐

  1. Don't make me think 摘录与读后感

    别让我思考 ——Krug可用性第一定律 点击多少次都没关系,只要每次点击都是无需思考,明确无误的选择.——Krug可用性第二定律 去掉每个页面上一般的文字, 然后把剩下的文字再去掉一半 ——Krug可 ...

  2. IOS 入门开发之创建标题栏UINavigationBar的使用(二)

    IOS 入门开发之创建标题栏UINavigationBar的使用 http://xys289187120.blog.51cto.com/3361352/685746     IOS 开发有关界面的东西 ...

  3. 异常:The absolute uri: http://www.springframework.org/security/tags cannot be resolved in either web.xml or the jar files deployed with this application

    The absolute uri: http://www.springframework.org/security/tags cannot be resolved in either web.xml ...

  4. 【Network】一张图看懂 Reactor 与 Proactor 模型的区别

    首先来看看Reactor模式,Reactor模式应用于同步I/O的场景.我们以读操作为例来看看Reactor中的具体步骤:读取操作:1. 应用程序注册读就需事件和相关联的事件处理器2. 事件分离器等待 ...

  5. 深入了解PooledConnectionFactory CachingConnectionFactory Sin

    深入理解PooledConnectionFactory CachingConnectionFactory SingleConnectionFactory PooledConnectionFactory ...

  6. css用标签选择器在本页写样式

    <title>静夜思</title><style type="text/css">p{ color:#ff0000;   font-size:2 ...

  7. local variable 'xxx' referenced before assignment

    这个问题很囧,在外面定义了一个变量 xxx ,然后在python的一个函数或类里面引用这个变量,并改变它的值,结果报错local variable 'xxx' referenced before as ...

  8. 【转】Solr安全设置——对外禁用管理后台

    本文转自:http://www.devnote.cn/article/94.html 测试于:Solr 4.5.1, Jdk 1.6.0_45, Tomcat 6.0.37 | CentOS 5.7 ...

  9. Android clickable 和 focusable

    setClickable(),好像是控制按钮是否可以被点击和点击之后触发监听器事件.setFocusable();控制键盘是否可以获得这个按钮的焦点.(我按实体键盘上方向键,button被选中) 今天 ...

  10. Windows系统时间同步出错解决办法

    有时候我们设置本地时间与Internet时间同步时,经常连接服务器time.windows.com超时,导致时间同步失败,解决办法如下: 利用快捷键"Win+R"调出运行框,输入: ...