求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
 
利用AOP重构代码

2010-07-21 作者:姜敏 来源:博客园

 

AOP是什么?  

AOP是OOP的延续,Aspect Oriented Programming的缩写,即面向方面编程。AOP是GoF设计模式的延续,设计模式追求的是调用者和被调用者之间的解耦,AOP也是这种目标的一 种实现。  

案例:在应用程序中,我们经常会对某一段程序做异常处理,或者是把一个方法的调用所消耗的时间体现在日志中,如果我们对每个方法都写具体的实现,我想并不是一件轻松的事情。对于异常处理来讲,其实我们平常编程很少去捕获具体的异常,当然特殊程序除外,例如客户端捕获WCF异常时最好捕获CommunicationException,TimeoutException,Exception。否则一般都会直接捕获Exception,因为很多异常往往是意料之外的异常。对于记录方法调用时间问题,我想也非常麻烦,下面例子简单的展示了记录时间:当你需要对多个方法都需要记录时间时,这些代码往往让人感觉有重构的必要。

Stopwatch sw = new Stopwatch();
   sw.Start();
   
//方法执行.....
   sw.Stop();
   WebLog.SquareLog.CommonLogger.Error(
"取积分广场首页酒店数据用时:"+sw.ElapsedMilliseconds .ToString ()+"毫秒");

上面的记录方法调用用时,如果抽象出来,其实有下列特性:

1:不是具体访问类的首要或主要功能,访问类主要功能是业务逻辑处理。

2:具体访问类的主要功能可以独立、区分开来的。

3:是这个系统的一个纵向切面,涉及多个类、多个类的方法。示意图如下:

aspect: 新的程序结构关注系统的纵向切面,例如这里的异常处理以及方法调用时间记录,这个新的程序结构就是aspect(方面),方面(aspect)应该有以下职责:提供一些必备的功能,对被访问对象实现特有功能,以保证所以方法在被执行时都能正常的执行异常处理或者是其它的功能。

AOP应用范围

1:Authentication 权限

2:Error handling 错误处理

3:logging, tracing, profiling and monitoring 记录跟踪 优化 校准

......

AOP具体实现:主要是利用泛型委托来实现AOP思想。但泛型委托有一个局限就是最多支持四个参数,当你的方法超过四个时就不太好应用AOP重构了。我最近分析了有以下三个地方我们可以对代码进行优化:

第一:普通方法异常处理:ErrorHandler类,实现类参考第二或者是第三。

客户端调用:

代码
string ErrorMethodText="取积分广场首页酒店数据异常:";
           list = ErrorWCFHandler .Invoke<ISearchHotelForSquare, List<HotelGenericInfo>>(cli, proxy => proxy.GetHotelGenericListForSquare(requestInfo).ToList() ); 

第二:客户端调用WCF的异常处理:ErrorWCFHandler。

代码:

代码
public  class ErrorWCFHandler
    {
       
public static void Invoke<TContract>(TContract proxy, Action<TContract> action, string MethodElapsedTimeText, string MethodErrorText)
        {
            Stopwatch sw = 
new Stopwatch();
            sw.Start();
            
try
            {
                action(proxy);
                (proxy 
as ICommunicationObject).Close();
            }
            
catch (CommunicationException ex)
            {
                (proxy 
as ICommunicationObject).Abort();
                
//Handle Exception             
                //throw;
                WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());
            }
            
catch (TimeoutException ex)
            {
                (proxy 
as ICommunicationObject).Abort();
                
//Handle Exception         
                //throw;
                WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());
            }
            
catch (Exception ex)
            {
                
//Handle Exception        
                //(proxy as ICommunicationObject).Close();      
                WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());
            }
            sw.Stop();

            WebLog.SquareLog.CommonLogger.Error(MethodElapsedTimeText + sw.ElapsedMilliseconds.ToString() + 
"毫秒");
        }
       
public static TReturn Invoke<TContract, TReturn>(TContract proxy, Func<TContract, TReturn> func, string MethodElapsedTimeText, string MethodErrorText)
        {
            Stopwatch sw = 
new Stopwatch();
            sw.Start();
            TReturn returnValue = 
default(TReturn);
            
try
            {
                returnValue = func(proxy);
            }
            
catch (CommunicationException ex)
            {
                (proxy 
as ICommunicationObject).Abort();
                
//Handle Exception     
                //throw;
                WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());
            }
            
catch (TimeoutException ex)
            {
                (proxy 
as ICommunicationObject).Abort();
                
//Handle Exception       
                //throw;
                WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());
            }
            
catch (Exception ex)
            {
                
//Handle Exception  
                WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());
            }
            sw.Stop();

            WebLog.SquareLog.CommonLogger.Error(MethodElapsedTimeText + sw.ElapsedMilliseconds.ToString() + 
"毫秒");
            
return returnValue;
        }
    }

客户端调用:

代码
string ComputationTimeText="取积分广场首页酒店数据耗时:";
           
string ErrorMethodText="取积分广场首页酒店数据异常:";
           list = ErrorWCFHandler .Invoke<ISearchHotelForSquare, List<HotelGenericInfo>>(cli, proxy => proxy.GetHotelGenericListForSquare(requestInfo).ToList

(),ComputationTimeText ,ErrorMethodText );  

第三:记录方法调用时间,这中间也增加了异常处理:ErrorAndComputationTimeHandler

代码:

代码
 public class ErrorAndComputationTimeHandler
    {
        
public static void Invoke<TContract>(TContract proxy, Action<TContract> action, string MethodElapsedTimeText,string MethodErrorText)
        {
            Stopwatch sw = 
new Stopwatch();
            sw.Start();
            
try
            {
                action(proxy);

            }
            
catch (Exception ex)
            {
                
//Handle Exception   
                WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());

            }
            sw.Stop();

            WebLog.SquareLog.CommonLogger.Error(MethodElapsedTimeText  + sw.ElapsedMilliseconds.ToString() + 
"毫秒");
        }
        
public static void Invoke<TContract, TContract2>(TContract proxy, TContract2 proxy2, Action<TContract,
 TContract2> action, 
string MethodElapsedTimeText,string MethodErrorText)
        {
            Stopwatch sw = 
new Stopwatch();
            sw.Start();
            
try
            {
                action(proxy, proxy2);

            }
            
catch (Exception ex)
            {
                
//Handle Exception   
                WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());

            }
            sw.Stop();

            WebLog.SquareLog.CommonLogger.Error(MethodElapsedTimeText  + sw.ElapsedMilliseconds.ToString() + 
"毫秒");
        }
        
public static void Invoke<TContract, TContract2, TContract3>(TContract proxy, TContract2 proxy2, TContract3 proxy3,
 Action<TContract, TContract2, TContract3> action, 
string MethodElapsedTimeText,string MethodErrorText)
        {
            Stopwatch sw = 
new Stopwatch();
            sw.Start();
            
try
            {
                action(proxy, proxy2, proxy3);

            }
            
catch (Exception ex)
            {
                
//Handle Exception   
                WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());

            }
            sw.Stop();

            WebLog.SquareLog.CommonLogger.Error(MethodElapsedTimeText  + sw.ElapsedMilliseconds.ToString() + 
"毫秒");
        }
        
public static void Invoke<TContract, TContract2, TContract3, TContract4>(TContract proxy, TContract2 proxy2,
 TContract3 proxy3, TContract4 proxy4, Action<TContract, TContract2, TContract3, TContract4> action,  
string MethodElapsedTimeText,string MethodErrorText)
        {
            Stopwatch sw = 
new Stopwatch();
            sw.Start();
            
try
            {
                action(proxy, proxy2, proxy3, proxy4);

            }
            
catch (Exception ex)
            {
                
//Handle Exception   
                WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());

            }
            sw.Stop();

            WebLog.SquareLog.CommonLogger.Error(MethodElapsedTimeText  + sw.ElapsedMilliseconds.ToString() + 
"毫秒");
        }
        
public static TReturn Invoke<TContract, TReturn>(TContract proxy, Func<TContract, TReturn> func,  string MethodElapsedTimeText,string MethodErrorText)
        {
            Stopwatch sw = 
new Stopwatch();
            sw.Start();
            TReturn returnValue = 
default(TReturn);
            
try
            {
                returnValue = func(proxy);
            }
            
catch (Exception ex)
            {
                
//Handle Exception   
                WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());

            }
            sw.Stop();

            WebLog.SquareLog.CommonLogger.Error(MethodElapsedTimeText  + sw.ElapsedMilliseconds.ToString() + 
"毫秒");
            
return returnValue;
        }
        
public static TReturn Invoke<TContract, TContract2, TReturn>(TContract proxy, TContract2 proxy2,
 Func<TContract, TContract2, TReturn> func,  
string MethodElapsedTimeText,string MethodErrorText)
        {
            Stopwatch sw = 
new Stopwatch();
            sw.Start();
            TReturn returnValue = 
default(TReturn);
            
try
            {
                returnValue = func(proxy, proxy2);
            }
            
catch (Exception ex)
            {
                
//Handle Exception   
                WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());

            }
            sw.Stop();

            WebLog.SquareLog.CommonLogger.Error(MethodElapsedTimeText  + sw.ElapsedMilliseconds.ToString() + 
"毫秒");
            
return returnValue;
        }
        
public static TReturn Invoke<TContract, TContract2, TContract3, TReturn>(TContract proxy, TContract2 proxy2, 
TContract3 proxy3, Func<TContract, TContract2, TContract3, TReturn> func,  
string MethodElapsedTimeText,string MethodErrorText)
        {
            Stopwatch sw = 
new Stopwatch();
            sw.Start();
            TReturn returnValue = 
default(TReturn);
            
try
            {
                returnValue = func(proxy, proxy2, proxy3);
            }
            
catch (Exception ex)
            {
                
//Handle Exception   
                WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());

            }
            sw.Stop();

            WebLog.SquareLog.CommonLogger.Error(MethodElapsedTimeText  + sw.ElapsedMilliseconds.ToString() + 
"毫秒");
            
return returnValue;
        }
        
public static TReturn Invoke<TContract, TContract2, TContract3, TContract4, TReturn>(TContract proxy, TContract2 proxy2,
 TContract3 proxy3, TContract4 proxy4, Func<TContract, TContract2, TContract3, TContract4, 
TReturn> func,  
string MethodElapsedTimeText,string MethodErrorText)
        {
            Stopwatch sw = 
new Stopwatch();
            sw.Start();
            TReturn returnValue = 
default(TReturn);
            
try
            {
                returnValue = func(proxy, proxy2, proxy3, proxy4);
            }
            
catch (Exception ex)
            {
                
//Handle Exception   
                WebLog.SquareLog.CommonLogger.Error(MethodErrorText + ex.ToString());

            }
            sw.Stop();
            WebLog.SquareLog.CommonLogger.Error(MethodElapsedTimeText  + sw.ElapsedMilliseconds.ToString() + 
"毫秒");
            
return returnValue;
        }
    }

客户端调用:

代码
string ComputationTimeText = "取酒店是否在积分广场首页推荐数据耗时:";
            
string ErrorMethodText = "取酒店是否在积分广场首页推荐数据异常:";
            
string conn = WebConfig.DaoConfig.MisMasterDBReadConnectionString;
            HotelRecommendInfo = ErrorAndComputationTimeHandler.Invoke<HotelRequestInfo, 
string, List<HotelGenericInfo>>(requestInfo, conn,
 SearchRecommendHotelData, ComputationTimeText, ErrorMethodText);

 

AOP的优势:

1:上述应用范例在没有使用AOP情况下,也能解决,但是,AOP可以让我们从一个更高的抽象概念来理解软件系统。可以这么说:因为使用AOP结构,对于一个大型复杂系统来说可以简化不少代码。

2:并不是所有的人都需要关心AOP,使得其它开发人员有更多精力去关注自己的业务逻辑。



如何向妻子解释OOD
OOAD与UML笔记
UML类图与类的关系详解
UML统一建模语言初学
总结一下领域模型的验证
基于 UML 的业务建模


面向对象的分析设计
基于UML的面向对象分析设计
UML + 嵌入式系统分析设计
关系数据库面向OOAD设计
业务建模与业务架构
使用用例进行需求管理


某航空IT部门 业务分析与业务建模
联想 业务需求分析与建模
北京航管科技 EA工具与架构设计
使用EA和UML进行嵌入式系统分析
全球最大的茶业集团 UML系统分析
华为 基于EA的嵌入式系统建模
水资源服务商 基于EA进行UML建模
更多...