引言
假如現在我們有這樣在這個示例中我將使用盡可能簡單的邏輯實現所有功能需求,這將更突出我們所要解決的核心問題。例子是一個簡單計算器類:
public class calculator
{
public int add(int x, int y) { return x + y; }
}
這個類再簡單不過了,不過若你將它想象為一個可能更復雜的業務處理類的時候,你將面臨除了核心功能實現之外的更多處理細節,比如說:權限控制、審計日志、性能監測、緩沖處理、事務環境等等。為簡單起見,我們首先為該類增加記錄日志的功能,該功能要求將對每個方法的調用和處理結果輸出到console中,如下:
public class calculator
{
public int add(int x, int y)
{
console.write("add({0},{1})", x, y);
int result = x + y;
console.writeline(" = {0}", result);
return result;
}
}
再簡單不過了,對吧?現在我們需要為該方法實現性能監測,如下:
public class calculator
{
public int add(int x, int y)
{
console.write("add({0},{1})", x, y);
datetime timebegin = system.datetime.now;
int result = x + y;
timespan timeinter =system.datetime.now-timebegin;
console.write(" [{0}] ", timeinter);
console.writeline(" = {0}", result);
return result;
}
}
此時你已經感覺到,雖然我們實現了所需的功能,但是在一個方法中堆疊了處理各類事宜的不同代碼。雖然在這個簡單例子中不會感覺有什么不爽,但是請你想象一下如果我們將為該類添加第二個方法時會發生什么事情:
public class calculator
{
public int add(int x, int y)
{
console.write("add({0},{1})", x, y);
datetime timebegin = system.datetime.now;
int result = x + y;
timespan timeinter =system.datetime.now-timebegin;
console.write(" [{0}] ", timeinter);
console.writeline(" = {0}", result);
return result;
}
public int subtract(int x, int y)
{
console.write("subtract({0},{1})", x, y);
datetime timebegin = system.datetime.now;
int result = x - y;
timespan timeinter =system.datetime.now-timebegin;
console.write(" [{0}] ", timeinter);
console.writeline(" = {0}", result);
return result;
}
}
在兩個方法中已經明顯出現重復代碼了,這可不是一個好的解決辦法——想想一下如果我們的計算器有10個方法呢?如果我們還有類似于計算器類的另外數十個類呢?如果我們還有更多的方法級功能要實現呢(權限控制、事務管理……)?在企業級應用開發中,這可是一個經常會遇的問題。為清楚起見,我們將問題分解成兩部分,首要的問題是代碼職責混淆,其次則是同樣的代碼邏輯反復多次——這些問題都將導致開發管理、代碼編寫與維護的各種困難。
方案一:自己手動編寫代理解決
1、首先 我們定義接口icalculator:
using system;
namespace proxy
{
public interface icalculator
{
int add(int x, int y);
int subtract(int x, int y);
}
}
2、具體實現一個接口:
using system;
namespace proxy
{
public class calculator:icalculator
{
public virtual int add(int x, int y)
{
int result = x + y;
return result;
}
public virtual int subtract(int x, int y)
{
int result = x - y;
return result;
}
}
}
3、編寫增加日志和性能檢測功能的代理類
增加記錄日志的功能,即功能要求將對每個方法的調用和處理結果輸出到console;增加性能監測。
有兩種實現方式 ,注釋了其中的一種
using system;
namespace proxy
{
// /// <summary>
// /// calproxy 的摘要說明。
// /// </summary>
// public class calproxy:icalculator
// {
// private calculator _calculator;
// public calproxy()
// {
// this._calculator=new calculator();
// }
// private datetime timebegin = system.datetime.now;
// private void predosomething(int x, int y)
// {
// timebegin = system.datetime.now;
// console.write("number({0},{1})/n", x, y);
// }
// //實現add
// public virtual int add(int x, int y)
// {
// this.predosomething(x,y);
// int result = this._calculator.add(x,y);
// this.postdosomething(result);
// return result;
// }
// //實現sub
// public virtual int subtract(int x, int y)
// {
// this.predosomething(x,y);
// int result = this._calculator.subtract(x,y);
// this.postdosomething(result);
// return result;
// }
// private void postdosomething(int result)
// {
// timespan timeinter =system.datetime.now-timebegin;
// console.write(" 運行時間[{0}]/n ", timeinter);
// console.writeline(" 運行結果= {0}/n", result);
// }
// }
/// <summary>
/// calproxy 的摘要說明。
/// </summary>
public class calproxy:calculator
{
public calproxy()
{}
private datetime timebegin = system.datetime.now;
private void predosomething(int x, int y)
{
timebegin = system.datetime.now;
console.write("number({0},{1})/n", x, y);
}
//實現add
public override int add(int x, int y)
{
this.predosomething(x,y);
int result = base.add(x,y);
this.postdosomething(result);
return result;
}
//實現sub
public override int subtract(int x, int y)
{
this.predosomething(x,y);
int result = base.subtract(x,y);
this.postdosomething(result);
return result;
}
private void postdosomething(int result)
{
timespan timeinter =system.datetime.now-timebegin;
console.write(" 運行時間[{0}]/n ", timeinter);
console.writeline(" 運行結果= {0}/n", result);
}
}
}
4、外界的調用方式
icalculator ical=new proxy.calproxy();
ical.add(5,3);
ical.subtract(7,2);
運行程序的結果:
number(5,3)
運行時間[00:00:02.0156250]
運行結果= 8
number(7,2)
運行時間[00:00:03]
運行結果= 5
方案二:通過使用castle.dynamicproxy,實現iinterceptor解決
步驟1,2與解決問題
3、實現standardinterceptor,增加日志和性能監測功能
standardinterceptor是接口iinterceptor的一個實現類,我們實現standardinterceptor
using system;
using system.collections;
using castle.dynamicproxy;
namespace proxy
{
/// <summary>
/// proxyinterceptor 攔截器 實現了日志和性能監測
/// </summary>
public class proxyinterceptor:standardinterceptor
{
private system.datetime timebegin=system.datetime.now;
public proxyinterceptor()
{}
protected override void postproceed(iinvocation invocation, ref object returnvalue, params object[] arguments)
{
timespan timeinter =system.datetime.now-timebegin;
console.write(" 運行時間[{0}]/n ", timeinter);
console.writeline(" 運行結果= {0}/n", returnvalue);
base.postproceed(invocation, ref returnvalue, arguments);
}
protected override void preproceed(iinvocation invocation, params object[] args)
{
console.write("number({0},{1})/n", args[0], args[1]);
timebegin=system.datetime.now;
base.preproceed(invocation, args);
}
public override object intercept(iinvocation invocation, params object[] args)
{
preproceed(invocation, args);
object retvalue = invocation.proceed( args );
postproceed(invocation, ref retvalue, args);
return retvalue;
}
}
}
4、使用castle.dynamicproxy調用
proxygenerator generator = new proxygenerator();
object proxy = generator.createclassproxy(typeof(calculator), new proxyinterceptor());
icalculator icalcastle=proxy as icalculator;
icalcastle.add(5,3);
icalcastle.subtract(7,2);
實現過程:首先通過代碼生成完成一個代理類,該代理類繼承自要織入的類。然后在代理類中覆蓋要攔截的方法,并在覆蓋的方法中封裝invocation對象,并傳給用戶傳入的intercepter對象的intercept方法。在intercept方法依次調用intercepter的preprocess,通過invocation傳入的delegate指向的回調函數,intercepter的postprocess方法,從而達到攔截的目的。
意義
在aop領域 可以將日志,事務,緩存等附加功能用此實現。菜鳥學堂: