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,使得其它開發人員有更多精力去關注自己的業務邏輯。

作者:姜敏
出處:HTTP://www.cnblogs.com/aspnet2008/
創作者介紹
創作者 shadow 的頭像
shadow

資訊園

shadow 發表在 痞客邦 留言(0) 人氣()