代理在實際中應用場景主要爲,在對一個已有的類的方法,進行先後記錄一些操做。如當一個程序的方法運行時先後,添加一些日誌記錄或時間記錄,以測量該方法運行所耗的時間。代理的實現分靜態代理和動態代理,靜態代理主要可經過繼承與聚合進行實現。其中繼承的實現,主要是在對須要添加代理的類進行擴展,而後按各類需求進行擴展,但此種方式的缺點是,若是同時須要兩個代理功能,如先記錄時間,而後記錄日誌,則可先讓時間記錄繼承業務類,而後日誌記錄繼承時間記錄。但若是還須要先日誌後記錄時間,則又得再次寫一套繼承。如此,會致使類無快速增長。聚合的實現,則只須要將所實現同一接口的業務類對象進行前後傳遞便可。如下一步步在此,僅以簡單的例子,一步步實現代理的實現原理。測試
1.基本的業務。假設有一個接口Runnable,如今讓一個Car去實現它this
namespace FD.Pattern.ConsoleApplicationProxy { // CreatedOn: 2016-04-12 // CreatedBy: Jackie Lee /// <summary> /// 移動的接口 /// </summary> interface Runnable { void Run(); } } namespace FD.Pattern.ConsoleApplicationProxy { // CreatedOn: 2016-04-12 // CreatedBy: Jackie Lee /// <summary> /// 汽車 /// </summary> public class Car : Runnable { public void Run() { Console.WriteLine("The car is running..."); Thread.Sleep(500); } } }
爲了後面能測試運行時間,在Car的實現中休息500毫秒。spa
2.新增要求。如今要求在不改變Car的狀況下,記錄下Car的Run運行時間,Car的Run狀況信息進行日誌記錄。如下使用聚合方式實現簡單的靜態代理pwa
namespace FD.Pattern.ConsoleApplicationProxy { // CreatedOn: 2016-04-12 // CreatedBy: Jackie Lee /// <summary> /// 汽車移動日期代理 /// </summary> public class CarRunDateProxy : Runnable { private Car car; public CarRunDateProxy(Car car) { this.car = car; } public void Run() { Stopwatch watch = Stopwatch.StartNew(); car.Run(); Console.WriteLine("Car Move {0} ms", watch.ElapsedMilliseconds); } } } namespace FD.Pattern.ConsoleApplicationProxy { // CreatedOn: 2016-04-12 // CreatedBy: Jackie Lee /// <summary> /// 汽車移動日誌代理 /// </summary> public class CarRunLogProxy : Runnable { private Car car; public CarRunLogProxy(Car car) { this.car = car; } public void Run() { Console.WriteLine("the car is begin to run..."); car.Run(); Console.WriteLine("the car stops running"); } } }
以下測試狀況,效果代理
namespace FD.Pattern.ConsoleApplicationProxy { // CreatedOn: 2016-04-12 // CreatedBy: Jackie Lee /// <summary> /// 主程序 /// </summary> class Program { static void Main(string[] args) { Car c = new Car(); CarRunDateProxy cmdp = new CarRunDateProxy(c); cmdp.Run(); Console.WriteLine("========================="); CarRunLogProxy cmlp = new CarRunLogProxy(c); cmlp.Run(); Console.ReadKey(); } } }
效果:日誌
爲了實現能夠同時組合多個代理,須要讓代理傳入的參數爲抽象爲接口Runnable,如下改進,如CarRunLogProxy將Car類型修改成Runnable接口,以下code
1 public class CarRunLogProxy : Runnable 2 { 3 private Runnable run; 4 public CarRunLogProxy(Runnable r) 5 { 6 this.run = r; 7 } 8 9 public void Run() 10 { 11 Console.WriteLine("the car is begin to run..."); 12 run.Run(); 13 Console.WriteLine("the car stops running"); 14 }
一樣將CarRunDateProxy中的Car也改成Runnable接口,此時,能夠實現任意組合進行記錄信息。對象
先記錄運行時間,現記錄運行日誌,在測試blog
1 Car c = new Car(); 2 CarRunDateProxy cmdp = new CarRunDateProxy(c); 3 Console.WriteLine("========================="); 4 5 Console.WriteLine("DateProxy, LogProxy"); 6 CarRunLogProxy cmlp = new CarRunLogProxy(cmdp); 7 cmlp.Run();
效果:繼承
先記錄日誌,而後記錄運行時間,則如:
CarRunLogProxy cmlp = new CarRunLogProxy(c); CarRunDateProxy cmdp = new CarRunDateProxy(cmlp); Console.WriteLine("========================="); Console.WriteLine("LogProxy,DateProxy"); cmdp.Run();