我們設計的分層架構,層與層之間應該是松散耦合的。因為是單向單一調用, 所以,這裡的“松散耦合”實際是指上層類不能具體依賴於下層類, 而應該依賴於下層提供的一個接口。這樣,上層類不能直接實例化下層中的類, 而只持有接口,至於接口所指變量最終究竟是哪一個類,則由依賴注入機制決定 。
之所以這樣做,是為了實現層與層之間的“可替換”式設計 ,例如,現在需要換一種方式實現數據訪問層,只要這個實現遵循了前面定義的 數據訪問層接口,業務邏輯層和表示層不需要做任何改動,只需要改一下配置文 件系統即可正常運行。另外,基於這種結構的系統,還可以實現並行開發。即不 同開發人員可以專注於自己的層次,只有接口被定義好了,開發出來的東西就可 以無縫連接。
在J2EE平台上,主要使用Spring框架實現依賴注入。這裡, 我們將自己做一個依賴注入容器。
依賴注入的理論基礎是Abstract Factory設計模式,這裡結合具體實例簡單介紹一下。
上圖以數據訪問層為例,展示了Abstract Factory模式的應用。如圖, 現假設有針對Access和SQLServer兩種數據庫的數據訪問層,它們都實現了數據訪 問層接口。每個數據訪問層有自己的工廠,所有工廠都實現自IDALFactory接口。 而客戶類(這裡就是業務邏輯層類)僅與工廠接口、數據訪問層接口耦合,而與 具體類無關,這樣,只要通過配置文件確定實例化哪個工廠,就可以得到不同的 數據訪問層。
然而,這種設計雖然可行,但是代碼比較冗余,因為這樣需 要為數據訪問層的每一個實現編寫一個工廠,業務邏輯層也一樣。在以前,我們 毫無辦法,但是,.NET平台引入的反射機制,給我們提供了一種解決方案。使用 反射,每個層只需要一個工廠,然後通過從配置文件中讀出程序集的名稱,動態 加載相應類。另外,為了提高依賴注入機制的效率,這裡引入緩存機制。下面來 看具體實現。
配置
首先,需要在Web工程的Web.config文件的 <appSettings>節點下添加如下兩個項:
<add key="DAL" value=""/>
<add key="BLL" value=""/>
這兩個配置選項分別存 儲要應用的數據訪問和也業務邏輯層的程序集名稱。value目前是空,是因為目前 還沒有各個層次的具體實現。
實現緩存操作輔助類
為實現緩存操 作,我們將緩存操作封裝成一個輔助類,放在Utility工程下,具體代碼如下:
CacheAccess.cs:
CacheAccess
1using System;
2using System.Web;
3using System.Web.Caching;
4
5namespace NGuestBook.Utility
6{
7 /**//// <summary>
8 /// 輔助類,用於緩存操作
9 /// </summary>
10 public sealed class CacheAccess
11 {
12 /**//// <summary>
13 /// 將對象加入 到緩存中
14 /// </summary>
15 /// <param name="cacheKey">緩存鍵</param>
16 /// <param name="cacheObject">緩存對象 </param>
17 /// <param name="dependency">緩存依賴項</param>
18 public static void SaveToCache(string cacheKey, object cacheObject, CacheDependency dependency)
19 {
20 Cache cache = HttpRuntime.Cache;
21 cache.Insert(cacheKey, cacheObject, dependency);
22 }
23
24 /**//// <summary>
25 /// 從緩存中取得對象,不存在則 返回null
26 /// </summary>
27 /// <param name="cacheKey">緩存鍵</param>
28 /// <returns>獲取的緩存對象</returns>
29 public static object GetFromCache(string cacheKey)
30 {
31 Cache cache = HttpRuntime.Cache;
32
33 return cache[cacheKey];
34 }
35 }
36}
封裝依賴注入代碼
因為很多依賴注入代碼非常相似,為了 減少重復性代碼,我們將可復用的代碼先封裝在一個類中。具體代碼如下(這個 類放在Factory工程下):
DependencyInjector.cs:
DependencyInjector
1usi ng System;
2using System.Configuration;
3using System.Reflection;
4using System.Web;
5using System.Web.Caching;
6using NGuestBook.Utility;
7
8namespace NGuestBook.Factory
9{
10 /**//// <summary>
11 /// 依賴注入提供者
12 /// 使用反射機 制實現
13 /// </summary>
14 public sealed class DependencyInjector
15 {
16 /**//// <summary>
17 /// 取得數據訪問層對象
18 /// 首先檢查緩存中是否存在,如果不存在,則利用反射機制返回對象
19 /// </summary>
20 /// <param name="className">數據訪問類名稱</param>
21 /// <returns>數據訪問層對象</returns>
22 public static object GetDALObject(string className)
23 {
24 /**//// <summary>
25 /// 取得數據 訪問層名稱,首先檢查緩存,不存在則到配置文件中讀取
26 /// 緩存依賴項為Web.Config文件
27 /// </summary>
28 object dal = CacheAccess.GetFromCache("DAL");
29 if (dal == null)
30 {
31 CacheDependency fileDependency = new CacheDependency (HttpContext.Current.Server.MapPath("Web.Config"));
32 dal = ConfigurationManager.AppSettings ["DAL"];
33 CacheAccess.SaveToCache ("DAL", dal, fileDependency);
34 }
35
36 /**//// <summary>
37 /// 取得數據 訪問層對象
38 /// </summary>
39 string dalName = (string)dal;
40 string fullClassName = dalName + "." + className;
41 object dalObject = CacheAccess.GetFromCache(className);
42 if (dalObject == null)
43 {
44 CacheDependency fileDependency = new CacheDependency (HttpContext.Current.Server.MapPath("Web.Config"));
45 dalObject = Assembly.Load(dalName).CreateInstance (fullClassName);
46 CacheAccess.SaveToCache (className, dalObject, fileDependency);
47 }
48
49 return dalObject;
50 }
51
52 /**//// <summary>
53 /// 取得業務邏輯層對象
54 /// 首先檢查緩存中是否存在,如果不存在,則利用反射機制返回 對象
55 /// </summary>
56 /// <param name="className">業務邏輯類名稱</param>
57 /// <returns>業務邏輯層對象</returns>
58 public static object GetBLLObject(string className)
59 {
60 /**//// <summary>
61 /// 取得業務 邏輯層名稱,首先檢查緩存,不存在則到配置文件中讀取
62 /// 緩存依賴項為Web.Config文件
63 /// </summary>
64 object bll = CacheAccess.GetFromCache("BLL");
65 if (bll == null)
66 {
67 CacheDependency fileDependency = new CacheDependency (HttpContext.Current.Server.MapPath("Web.Config"));
68 bll = ConfigurationManager.AppSettings ["BLL"];
69 CacheAccess.SaveToCache ("BLL", bll, fileDependency);
70 }
71
72 /**//// <summary>
73 /// 取得業務 邏輯層對象
74 /// </summary>
75 string bllName = (string)bll;
76 string fullClassName = bllName + "." + className;
77 object bllObject = CacheAccess.GetFromCache(className);
78 if (bllObject == null)
79 {
80 CacheDependency fileDependency = new CacheDependency (HttpContext.Current.Server.MapPath("Web.Config"));
81 bllObject = Assembly.Load(bllName).CreateInstance (fullClassName);
82 CacheAccess.SaveToCache (className, bllObject, fileDependency);
83 }
84
85 return bllObject;
86 }
87 }
88}
實現工廠
下面使用兩個輔助類,實現數據訪問層工 廠和業務邏輯層工廠。
DALFactory.cs
DALFactory
1using System;
2using NGuestBook.IDAL;
3
4namespace NGuestBook.Factory
5{
6 /**//// <summary>
7 /// 數據訪問層工廠,用 於獲取相應的數據訪問層對象
8 /// 使用Abstract Factory設計模式 +Facace設計模式+反射機制+緩存機制設計
9 /// </summary>
10 public sealed class DALFactory
11 {
12 /**//// <summary>
13 /// 獲取管理員數據訪問層對象
14 /// </summary>
15 /// <returns> 管理員數據訪問層對象</returns>
16 public static IAdminDAL CreateAdminDAL()
17 {
18 return (IAdminDAL)DependencyInjector.GetDALObject("AdminDAL");
19 }
20
21 /**//// <summary>
22 /// 獲取留言數據訪問層對象
23 /// </summary>
24 /// <returns>留言數據訪問層對象</returns>
25 public static IMessageDAL CreateMessageDAL()
26 {
27 return (IMessageDAL) DependencyInjector.GetDALObject("MessageDAL");
28 }
29
30 /**//// <summary>
31 /// 獲取評論數據訪問層對象
32 /// </summary>
33 /// <returns>評論數據訪問層對象</returns>
34 public static ICommentDAL CreateCommentDAL()
35 {
36 return (ICommentDAL)DependencyInjector.GetDALObject ("CommentDAL");
37 }
38 }
39}
BLLFactory.cs
BLLFactory
1using System;
2using NGuestBook.IBLL;
3
4namespace NGuestBook.Factory
5{
6 /**//// <summary>
7 /// 業務邏輯層工廠,用於獲取相應的業務邏輯層對象
8 /// 使用 Abstract Factory設計模式+Facace設計模式+反射機制+緩存機制設計
9 /// </summary>
10 public sealed class BLLFactory
11 {
12 /**//// <summary>
13 /// 獲 取管理員業務邏輯層對象
14 /// </summary>
15 /// <returns>管理員業務邏輯層對象</returns>
16 public static IAdminBLL CreateAdminBLL()
17 {
18 return (IAdminBLL)DependencyInjector.GetBLLObject ("AdminBLL");
19 }
20
21 /**//// <summary>
22 /// 獲取留言業務邏輯層對象
23 /// </summary>
24 /// <returns>留言業務邏輯層 對象</returns>
25 public static IMessageBLL CreateMessageBLL()
26 {
27 return (IMessageBLL)DependencyInjector.GetBLLObject ("MessageBLL");
28 }
29
30 /**//// <summary>
31 /// 獲取評論業務邏輯層對象
32 /// </summary>
33 /// <returns>評論 業務邏輯層對象</returns>
34 public static ICommentBLL CreateCommentBLL()
35 {
36 return (ICommentBLL)DependencyInjector.GetBLLObject ("CommentBLL");
37 }
38 }
39}