當設計一個應用程式時,基本的要求是所有的通信資訊互動都要通過定義的接口進行,不能讓應用程式直接調用該接口的類别或方法。是以,可以通過Layer Diagram來展示這個架構上的想法。
我們将使用一段非常簡單的代碼,主要強調的是代碼所代表的概念,而不是代碼的細節。并将在現有代碼層關系架構邏輯設計分析的基礎上進行層驗證(Layer Validation)功能:
①打開Visual Studio 2010,通過Modeling Projects模闆指定解決方案(Solution)的名稱為LayerValidation(File|New|Project指令,選擇ModelingProject,命名為LayerValidation),并提供建立一個名為“Client”的C#控制台程式,單擊“OK”按鈕。
②在解決方案浏覽器中,使用滑鼠右鍵單擊Solution節點,選擇“New Project…”指令,在彈出的對話框中選擇“Class Library”并将工程命名為“Implementation”。
③重複以上幾步,建立名為“Interfaces”和“Creators”的Class Library工程。展開Interfaces工程節點,用滑鼠右鍵單擊Class1.cs,選擇“Rename”指令,将該檔案重命名為“IDataRetriever.cs”,并在彈出的對話框中選擇“Yes”。文檔編輯視窗和Solution Explorer如圖5所示。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiInBnaukTY4MzYygjYxUmZycjZkFGNzQmY5gTO3kzNwEGM0MjNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.jpg)
圖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檔案,并在檔案中建立一個名為IData的接口。
⑤展開Implementation工程節點,用滑鼠右鍵單擊References節點,選擇“Add Reference…”指令,在彈出的對話框中選擇Projects頁,然後選擇Interfaces工程,單擊“OK”按鈕。
⑥将Class1.cs重命名為DataRetriever.cs。打開DataRetriever.cs檔案,修改DataRetriever類使其實作IDataRetriever接口。當輸入IDataRetriever的時候沒有出現智能輸入支援,可以手動輸入IDataRetriever,然後會發現IDataRetriever下面又出現了紅色波浪線。将滑鼠移動到IDataRetriever上,會注意到在這個單詞開始的位置下方有一個方形的小圖示。單擊它并選擇“using Interfaces;”指令,它會自動為你添加所需的using語句,如圖6所示。
圖6 自動化提示添加代碼語句(名字空間)
現在“using Interfaces”已經自動添加好了。再次選中這個圖示,不過這次選擇“Implement interface ‘IDataRetriever’”指令,可自動生成“DataRetriever”代碼檔案。如上所示,建立了一個對象,調用了對象的一個屬性,然後抛出一個“NotImplementedException”異常,程式描述了一個實際系統中經常遇到的問題。
⑧接下來向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)。在沒有需求功能擴充前沒有太大問題,因為所有的資料是從DataRetriever中擷取(可以想象DataRetriever是從SQL資料庫中擷取的資料)。如果将來需要從另一種資料源中擷取資料,在不改動應用程式其他部分的情況下實作需求,可以使用Layer Diagram和Layer Validation來保證開發代碼不會違反這一設計。
我們可以不對接口的具體實作做任何設定,而僅僅依賴于接口本身。這是一個相當普遍的設計模式,但是在現實應用中很容易被違反。隻要一行錯誤的代碼就會破壞這個模式,進而在建立子產品間出現了不必要的依賴關系(通常使用控制反轉(IoC)來解決這個問題)。
⑨建立Layer Diagram。可以建立一個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 建立映射
如上圖所示,然後建立各個層次之間的互相關系。從工具箱中選擇Dependency工具,在Solution Explorer中,選中Client工程并将它拖曳到Layer Diagram上的Client Logic層上,代表Client層會依賴Interface層。這時出現了一個由Client指向Interface的箭頭連結。将Interfaces工程拖到Interfaces層上;最後,将Implementation工程拖到Implementation層上,代表Implementation層會依賴Interface層;在層右上角的數字“1”表示該層已經和一個工程相關聯。
如果選中Client Logic、Interfaces和Implementation層,再打開Layer Explorer,就可以看到和目前層關聯的項目,這裡是Client.exe、Interfaces.dll和Implementation.dll,然後就可以用這張圖來對代碼進行限制與驗證,如圖8所示。
圖8 進行架構驗證
如上圖所示,進行架構驗證。用滑鼠右鍵單擊Layer Diagram的任何位置,選擇“Validate Architecture”指令,進行驗證。
驗證架構(Validate Architecture):可以檢查出我們的程式是否破壞了層次圖中的依賴關系,如果我們的程式中的CaryLayer項目中的程式調用了Common項目中的類等于就違反了以前設計好的層次圖,在驗證架構的時候就會失敗。
依賴關系(Generate Dependencies):可以根據我們程式中的調用關系生成層的依賴關系。
錯誤清單。指令執行完成後會看到“Error List”視窗中有三條錯誤資訊,同時訓示錯誤發生的區域。檢視一下錯誤内容,會發現我們要求的層次依賴關系被破壞了。這是因為Client工程中的Program.cs直接使用了Implementation工程中定義的類型。而在剛才建立的圖中,這種依賴關系是錯誤的,如圖3錯誤清單提示。
修正代碼,解決錯誤問題。
打開Program.cs檔案,需要確定隻使用Interfaces工程中定義的類型,而不能直接使用Implementation工程中定義的類型。我們需要在不産生直接依賴關系的情況下建立實作IDataRetriever接口的對象。
解決方法是使用Factory模式,利用Factory建立以接口為主的方法。當以後要傳回的資訊接收器是針對不同的資訊來源進行處理的,隻要調整Factory方法傳回對應的接收器即可,原本的應用程式不用改動,因為它都是通過接口決定作業的,隻要實做了同樣接口的類都可以套用,進而增加了程式的彈性和維護能力。使用工廠(Factory)模式來解決這個問題的步驟如下:
在Solution Explorer中展開Creators工程,将Class1.cs重命名為TypeCreator.cs。
向Creators工程中添加對Implementation和“Interfaces”工程的引用(Creators工程現在依賴于Implementation和Interfaces工程)。
打開TypeCreators.cs,向其中添加一個靜态方法,該方法傳回一個IDataRetriever的對象。
代碼參考如下所示:
using System.Linq;
namespace Creators
public class TypeCreator
public static IDataRetriever CreateDataRetriever()
return new DataRetriever();
在Client工程中,移除對Implementation工程的引用,添加對Creators工程的引用。
修改Program.cs,使用剛才新加的方法來建立對象。代碼參考如下所示:
using Creators;
IDataRetriever dr = new TypeCreator.CreateDataRetriever();
重新編譯Solution,并重新打開FirstLayerDiagram,用滑鼠右鍵單擊,在菜單中執行“Validate Architecture”指令。這樣我們就不是直接通過實做的類進行資訊的存取,而是經由Factory取得符合接口定義的内容。再做一次層驗證,我們會看到所有的錯誤都消失了。
總結:通過使用Visual Studio 2010層關系設計架構,我們就可以在開始階段通過層關系圖來進行邏輯設計,并努力執行設計方案,保證開發階段與設計不偏離,通過自動化(例如門控簽入)進行強制執行,使團隊人員的代碼不漂移出架構,進而避免“漂移”發生。另外,采用Layer Diagram來驗證代碼架構的方法,大型項目也可以通過相同的方式進行驗證。這包括如何将代碼映射到層上,以及如何通過手動的方式來驗證代碼是否遵守定義的限制關系,也可以在編譯代碼的過程中自動地進行驗證。