Visual Studio 2010層架構驗證的實現(xiàn)
原創(chuàng)【51CTO獨家特稿】當設計一個應用程序時,基本的要求是所有的通信信息交互都要通過定義的接口進行,不能讓應用程序直接調用該接口的類別或方法。所以,可以通過Layer Diagram來展示這個架構上的想法。51CTO向您推薦《用好Visual Studio 2010進行層架構設計》
我們將使用一段非常簡單的代碼,主要強調的是代碼所代表的概念,而不是代碼的細節(jié)。并將在現(xiàn)有代碼層關系架構邏輯設計分析的基礎上進行層驗證(Layer Validation)功能:
①打開Visual Studio 2010,通過Modeling Projects模板指定解決方案(Solution)的名稱為LayerValidation(File|New|Project命令,選擇ModelingProject,命名為LayerValidation),并提供創(chuàng)建一個名為“Client”的C#控制臺程序,單擊“OK”按鈕。
②在解決方案瀏覽器中,使用鼠標右鍵單擊Solution節(jié)點,選擇“New Project…”命令,在彈出的對話框中選擇“Class Library”并將工程命名為“Implementation”。
③重復以上幾步,創(chuàng)建名為“Interfaces”和“Creators”的Class Library工程。展開Interfaces工程節(jié)點,用鼠標右鍵單擊Class1.cs,選擇“Rename”命令,將該文件重命名為“IDataRetriever.cs”,并在彈出的對話框中選擇“Yes”。文檔編輯窗口和Solution Explorer如圖5所示。
圖5 文檔編輯窗口和Solution Explorer
④把class的關鍵字改為interface,將IDataRetriever變成一個接口。為IDataRetriever添加一個get屬性,該屬性返回一個IData類型的對象。在IData下面有紅色波浪線,表示IData不存在。Visual Studio 2010的新功能可以自動解決這個問題:用鼠標右鍵單擊出錯的IData,選擇“Generate”命令,然后選擇“Other…”命令,將看到一個“New Type”對話框。將其中的“Access:”修改為“public”,將“Kind:”修改為“interface”,其他的保留默認設置,單擊“OK”按鈕。VS會自動向Interfaces工程添加一個IData.cs文件,并在文件中創(chuàng)建一個名為IData的接口。
⑤展開Implementation工程節(jié)點,用鼠標右鍵單擊References節(jié)點,選擇“Add Reference…”命令,在彈出的對話框中選擇Projects頁,然后選擇Interfaces工程,單擊“OK”按鈕。
⑥將Class1.cs重命名為DataRetriever.cs。打開DataRetriever.cs文件,修改DataRetriever類使其實現(xiàn)IDataRetriever接口。當輸入IDataRetriever的時候沒有出現(xiàn)智能輸入支持,可以手動輸入IDataRetriever,然后會發(fā)現(xiàn)IDataRetriever下面又出現(xiàn)了紅色波浪線。將鼠標移動到IDataRetriever上,會注意到在這個單詞開始的位置下方有一個方形的小圖標。單擊它并選擇“using Interfaces;”命令,它會自動為你添加所需的using語句,如圖6所示。
圖6 自動化提示添加代碼語句(名字空間)
現(xiàn)在“using Interfaces”已經(jīng)自動添加好了。再次選中這個圖標,不過這次選擇“Implement interface ‘IDataRetriever’”命令,可自動生成“DataRetriever”代碼文件。如上所示,創(chuàng)建了一個對象,調用了對象的一個屬性,然后拋出一個“NotImplementedException”異常,程序描述了一個實際系統(tǒng)中經(jīng)常遇到的問題。
⑧接下來向Client工程中添加到Implementation和Interfaces工程的引用。打開Client工程中的Program.cs文件,參考代碼如下:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using Implementation;
- using Interfaces;
- namespace Client
- {
- class Program
- {
- static void Main(string[] args)
- {
- DataRetriever dr = new DataRetriever();
- IData data = dr.Data;
- }
- }
- }
在這段代碼中,Client工程直接訪問了一個接口(IDataRetriever)的實例(DataRetriever)。在沒有需求功能擴展前沒有太大問題,因為所有的數(shù)據(jù)是從DataRetriever中獲?。梢韵胂驞ataRetriever是從SQL數(shù)據(jù)庫中獲取的數(shù)據(jù))。如果將來需要從另一種數(shù)據(jù)源中獲取數(shù)據(jù),在不改動應用程序其他部分的情況下實現(xiàn)需求,可以使用Layer Diagram和Layer Validation來保證開發(fā)代碼不會違反這一設計。
我們可以不對接口的具體實現(xiàn)做任何設置,而僅僅依賴于接口本身。這是一個相當普遍的設計模式,但是在現(xiàn)實應用中很容易被違反。只要一行錯誤的代碼就會破壞這個模式,從而在建立模塊間出現(xiàn)了不必要的依賴關系(通常使用控制反轉(IoC)來解決這個問題)。
⑨創(chuàng)建Layer Diagram。可以創(chuàng)建一個Layer Diagram來可視化地描述在架構中想要維護的約束關系。單擊主菜單的Architecture|New Diagram命令,選擇“Layer Diagram”命令,并將層圖命名為“FirstLayerDiagram.layerdiagram”,在彈出的對話框中,將工程命名為“FirstModelingProject”。
⑩塑模范本,將代碼映射到層上。在Layer Diagram Designer中,從工具箱中拖曳出三個Layer工具到設計平面上,分別由上至下指定層的名稱為Client、Interface、Implementation,代表應用程序、工作接口和方法。表示的是Client Logic層依賴于Interfaces層,Implementation層同樣依賴于Interfaces層。但是Client Logic層和Implementation層之間沒有依賴關系,如圖7所示。
圖7 創(chuàng)建映射
如上圖所示,然后建立各個層次之間的相互關系。從工具箱中選擇Dependency工具,在Solution Explorer中,選中Client工程并將它拖曳到Layer Diagram上的Client Logic層上,代表Client層會依賴Interface層。這時出現(xiàn)了一個由Client指向Interface的箭頭鏈接。將Interfaces工程拖到Interfaces層上;***,將Implementation工程拖到Implementation層上,代表Implementation層會依賴Interface層;在層右上角的數(shù)字“1”表示該層已經(jīng)和一個工程相關聯(lián)。
如果選中Client Logic、Interfaces和Implementation層,再打開Layer Explorer,就可以看到和當前層關聯(lián)的項目,這里是Client.exe、Interfaces.dll和Implementation.dll,然后就可以用這張圖來對代碼進行約束與驗證,如圖8所示。
圖8 進行架構驗證
如上圖所示,進行架構驗證。用鼠標右鍵單擊Layer Diagram的任何位置,選擇“Validate Architecture”命令,進行驗證。
驗證架構(Validate Architecture):可以檢查出我們的程序是否破壞了層次圖中的依賴關系,如果我們的程序中的CaryLayer項目中的程序調用了Common項目中的類等于就違反了以前設計好的層次圖,在驗證架構的時候就會失敗。
依賴關系(Generate Dependencies):可以根據(jù)我們程序中的調用關系生成層的依賴關系。
錯誤列表。命令執(zhí)行完成后會看到“Error List”窗口中有三條錯誤信息,同時指示錯誤發(fā)生的區(qū)域。檢視一下錯誤內容,會發(fā)現(xiàn)我們要求的層次依賴關系被破壞了。這是因為Client工程中的Program.cs直接使用了Implementation工程中定義的類型。而在剛才創(chuàng)建的圖中,這種依賴關系是錯誤的,如圖3錯誤列表提示。
修正代碼,解決錯誤問題。
打開Program.cs文件,需要確保只使用Interfaces工程中定義的類型,而不能直接使用Implementation工程中定義的類型。我們需要在不產(chǎn)生直接依賴關系的情況下創(chuàng)建實現(xiàn)IDataRetriever接口的對象。
解決方法是使用Factory模式,利用Factory建立以接口為主的方法。當以后要傳回的信息接收器是針對不同的信息來源進行處理的,只要調整Factory方法傳回對應的接收器即可,原本的應用程序不用改動,因為它都是通過接口決定作業(yè)的,只要實做了同樣接口的類都可以套用,從而增加了程序的彈性和維護能力。使用工廠(Factory)模式來解決這個問題的步驟如下:
在Solution Explorer中展開Creators工程,將Class1.cs重命名為TypeCreator.cs。
向Creators工程中添加對Implementation和“Interfaces”工程的引用(Creators工程現(xiàn)在依賴于Implementation和Interfaces工程)。
打開TypeCreators.cs,向其中添加一個靜態(tài)方法,該方法返回一個IDataRetriever的對象。
代碼參考如下所示:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using Implementation;
- using Interfaces;
- namespace Creators
- {
- public class TypeCreator
- {
- public static IDataRetriever CreateDataRetriever()
- {
- return new DataRetriever();
- }
- }
- }
在Client工程中,移除對Implementation工程的引用,添加對Creators工程的引用。
修改Program.cs,使用剛才新加的方法來創(chuàng)建對象。代碼參考如下所示:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using Interfaces;
- using Creators;
- namespace Client
- {
- class Program
- {
- static void Main(string[] args)
- {
- IDataRetriever dr = new TypeCreator.CreateDataRetriever();
- IData data = dr.Data;
- }
- }
- }
修正代碼,解決錯誤問題。
重新編譯Solution,并重新打開FirstLayerDiagram,用鼠標右鍵單擊,在菜單中執(zhí)行“Validate Architecture”命令。這樣我們就不是直接通過實做的類進行信息的存取,而是經(jīng)由Factory取得符合接口定義的內容。再做一次層驗證,我們會看到所有的錯誤都消失了。
總結: 通過使用Visual Studio 2010層關系設計架構,我們就可以在開始階段通過層關系圖來進行邏輯設計,并努力執(zhí)行設計方案,保證開發(fā)階段與設計不偏離,通過自動化(例如門控簽入)進行強制執(zhí)行,使團隊人員的代碼不漂移出架構,從而避免“漂移”發(fā)生。另外,采用Layer Diagram來驗證代碼架構的方法,大型項目也可以通過相同的方式進行驗證。這包括如何將代碼映射到層上,以及如何通過手動的方式來驗證代碼是否遵守定義的約束關系,也可以在編譯代碼的過程中自動地進行驗證。
【編輯推薦】