概念介紹
類圖如下:
在常見的用例場景下,類圖的對象圖如下:
問題
在一個用例執行過程中,如何保證同一個界限上下文內的所有倉儲實例可以共享同一個工作單元實例?
解決方案1
倉儲采用依賴注入模式 + 使用IOC管理工作單元的生命周期(PerRequest或其它)。
代碼示例
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 using Autofac; 8 9 namespace AutoFacStudy 10 { 11 class Program 12 { 13 static void Main(string[] args) 14 { 15 var buider = new ContainerBuilder(); 16 buider.RegisterType<服務>(); 17 buider.RegisterType<倉儲A>(); 18 buider.RegisterType<倉儲B>(); 19 buider.RegisterType<工作單元>().InstancePerLifetimeScope(); 20 21 var container = buider.Build(); 22 23 dynamic 服務 = container.Resolve<服務>(); 24 25 //下邊兩行代碼輸出一樣 26 Console.WriteLine(服務.倉儲A.工作單元.GetHashCode()); 27 Console.WriteLine(服務.倉儲B.工作單元.GetHashCode()); 28 } 29 } 30 31 public class 服務 32 { 33 private readonly 倉儲A _倉儲A; 34 private readonly 倉儲B _倉儲B; 35 36 public 服務(倉儲A 倉儲A, 倉儲B 倉儲B) 37 { 38 _倉儲A = 倉儲A; 39 _倉儲B = 倉儲B; 40 } 41 42 public 倉儲A 倉儲A 43 { 44 get { return _倉儲A; } 45 } 46 47 public 倉儲B 倉儲B 48 { 49 get { return _倉儲B; } 50 } 51 } 52 53 public class 工作單元 { } 54 55 public class 倉儲A 56 { 57 private readonly 工作單元 _工作單元; 58 59 public 倉儲A(工作單元 工作單元) 60 { 61 _工作單元 = 工作單元; 62 } 63 64 public 工作單元 工作單元 65 { 66 get { return _工作單元; } 67 } 68 } 69 70 public class 倉儲B 71 { 72 private readonly 工作單元 _工作單元; 73 74 public 倉儲B(工作單元 工作單元) 75 { 76 _工作單元 = 工作單元; 77 } 78 79 public 工作單元 工作單元 80 { 81 get { return _工作單元; } 82 } 83 } 84 }
解決方案2
倉儲采用服務定位器模式 + 使用服務定位器或簡單工廠管理工作單元的生命周期(PerRequest或其它)。
代碼示例
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 using Autofac; 8 9 namespace AutoFacStudy 10 { 11 class Program 12 { 13 public static IContainer 服務定位器; 14 15 static void Main(string[] args) 16 { 17 var buider = new ContainerBuilder(); 18 buider.RegisterType<服務>(); 19 buider.RegisterType<倉儲A>(); 20 buider.RegisterType<倉儲B>(); 21 buider.RegisterType<工作單元>().InstancePerLifetimeScope(); 22 23 服務定位器 = buider.Build(); 24 25 dynamic 服務 = 服務定位器.Resolve<服務>(); 26 27 //下邊兩行代碼輸出一樣 28 Console.WriteLine(服務.倉儲A.工作單元.GetHashCode()); 29 Console.WriteLine(服務.倉儲B.工作單元.GetHashCode()); 30 } 31 } 32 33 public class 服務 34 { 35 private readonly 倉儲A _倉儲A; 36 private readonly 倉儲B _倉儲B; 37 38 public 服務(倉儲A 倉儲A, 倉儲B 倉儲B) 39 { 40 _倉儲A = 倉儲A; 41 _倉儲B = 倉儲B; 42 } 43 44 public 倉儲A 倉儲A 45 { 46 get { return _倉儲A; } 47 } 48 49 public 倉儲B 倉儲B 50 { 51 get { return _倉儲B; } 52 } 53 } 54 55 public class 工作單元 { } 56 57 public class 倉儲A 58 { 59 private readonly 工作單元 _工作單元; 60 61 public 倉儲A() 62 { 63 _工作單元 = Program.服務定位器.Resolve<工作單元>(); 64 } 65 66 public 工作單元 工作單元 67 { 68 get { return _工作單元; } 69 } 70 } 71 72 public class 倉儲B 73 { 74 private readonly 工作單元 _工作單元; 75 76 public 倉儲B() 77 { 78 _工作單元 = Program.服務定位器.Resolve<工作單元>(); 79 } 80 81 public 工作單元 工作單元 82 { 83 get { return _工作單元; } 84 } 85 } 86 }
由此示例可以看出,服務定位器和依賴注入可以混合在一起使用。這個例子我為了簡單,服務定位器和IOC容器是同一個實例。
有些系統將服務定位器的實現換成簡單工廠模式,他們本質上是一樣的(服務定位器是一個萬能工廠)。
代碼示例
1 public class 工作單元工廠 2 { 3 public static 工作單元 創建() 4 { 5 var 工作單元 = (工作單元)CallContext.GetData("工作單元"); 6 7 if (工作單元 == null) 8 { 9 工作單元 = new 工作單元(); 10 CallContext.SetData("工作單元", 工作單元); 11 } 12 13 return 工作單元; 14 } 15 }