共用方式為


VSTS 2010 Layer Diagram

原文出處:http://michaelchpeng.spaces.live.com/blog/cns!37633C3B61B57B57!1112.entry


當我們在做架構設計時,一開始最常碰到的就是決定系統的分層狀況,像是三層式架構中的使用者介面、商務邏輯和資料存取。而就開發的角度來看,理應是使用者介面只能透過商務邏輯層去存取資料層。不過在實際開發時,我們不經意的繞道而行是常見的事。如何讓開發出來的東西真的能遵循我們原本設計的架構,不致產生違背設計 (以致後續難以維護) 的情況,是個大挑戰。Visual Studio Team System 2010 的 Layer Diagram 讓架構設計和開發成果之間的驗證簡單許多,這裡就用一個簡單的例子看看。我使用的是 Beta 2 的版本。

想法是這樣,我們要設計一個應用程式,基本的要求是所有的通訊作業都要透過定義的介面進行,不能讓應用程式直接呼叫實作了該介面的類別或方法 (有點 WCF 的感覺)。我們可以透過 Layer Diagram 來表達這個架構上的想法。我啟動了 VSTS 2010,試著建立一個新專案,我們可以看到在左邊的範本類型中有一個 Modeling Projects 節點,選擇右方的 Modeling Project 範本,我們指定解決方案的名稱為 LayerValidation,並提供專案的名稱為 SimpleModel。


建立塑模專案

接著我們在 SimpkeModel 專案中加入新的項目,可以看到在新增項目的對話方塊中提供了七種範本 (在 Beta 2 中新增加了一個 Directed Graph Document 範本),選擇 Layer Diagram,同時命名為 FundamentalLayer。


塑模用的範本

在 Layer Diagram Designer 中,我們從工具箱中拖放出三個 Layer 工具到設計平面上,分別由上至下指定層的名稱為 Client、Interface、Implementation,代表我們的應用程式、作業介面和實作方法。接著我們要建立各個層次之間的相依關係。按照我們的設計,從工具箱點選 Dependency 工具,然後從 Client 層拖放到 Interface 層,代表 Client 層會依賴 Interface 層。這時出現一個由 Client 指向 Interface 的箭頭連線。以同樣的方式建立 Implementation 層依賴 Interface 層的連結,如下圖所示:


Layer Diagram

這是我們要求的架構,接著我們可以在解決方案中再加入四個方案,第一個方案是一個 Console Application 專案,名稱為 Client。至於其他三個專案則都是 Class Library 專案,名稱分別是 Interface、Implementation、Creator。我這裡用的例子是 VB,架構是和語言無關的,所以同樣的功能也適用在 C# 上。

我這裡要建立的是一個簡單的例子,我們要定義一個標準的訊息介面做為資料定義,以及一個方法介面用以傳回訊息。所以我打開 Interface 介面專案,將原本預設的 Class1 改成 IMessageReceiver,原本預設的宣告是 Class,當我改成 Interface 時,就會出現宣告是 Interface,但結尾是 Class 的情況。於是 2010 除了如過往透過破折線標示文法錯誤之外,同時也透過 Smart Tag 提供修正的選項。把滑鼠停在破折線標示區,就會出現 Smart Tag,然後我可以選擇 Insert the missing "End Interface" 的命令。點選之後就會自動補上正確的結尾敘述,我們再把多餘的 End Class 刪除就可以。


Smart Tag

在 IMessageReceiver 介面中,我們要定義一個僅讀的 Message 屬性,它的型別也是一個介面 ─ IMessage。所以我們輸入以下的敘述:

ReadOnly Property Message As IMessage
很顯然的,IMessage 是一個我們還未定義的訊息介面,所以下方會出現警告的破折號。如果我們檢視一下對應的 Smart Tag,會發現其中有幾個命令,有一個是 Generate "Interface IMessage" (如果是 C#,可能是不一樣的命令,可以選擇Generate new type 命令透過對話盒指定要產生的是新介面)。我們只要選擇這個命令,就會自動產生另一個檔案並宣告這個介面。這個新功能可以讓我們不用先定義新方法或型別,以更直覺更快速的方式建立正確的宣告。

好了,介面定義完畢,接著要建立實做的方法了。展開 Implementation 專案,加入對 Interface 的參考,因為我們要實做支援 IMessageReceiver 介面的類別。將預設的 Class1 類別改名稱為 MessageReceiver,然後加上實做的敘述:

Implements IMessageReceiver
由於我們並未匯入 Interface 命名空間,所以上述的宣告中 IMessageReceiver 的部份會被標示錯誤。同樣透過 Smart Tag,看到了幾個選項,一個是匯入正確的命名空間,一個是採用全稱來宣告型別。讚別,現在寫程式也可以像在 Microsoft Word 裡面寫文章一樣利用 Smart Tag 進行修正。我選擇了 Import Interface 命令 (在 C# 中就是 using Interface 了),就自動在檔案開發加上匯入的宣告。這個功能真的太酷了!

由於我們還要實做對應的介面屬性 Message,目前的情況是還沒有實做,所以設計師還是會提示錯誤。我在 Implements IMesasgeReceiver 後方敲下 Enter,讓系統自動幫我們建立一個實做的宣告 (如果是 C# 可能要透過 Smart Tag 產生),並且指定 NotImplementException,因為我們只是個例子,並沒有真正的傳回邏輯。到這裡,算是實做的部份完成。


實做部份

有了介面,有了實做的類別,接著就可以建立主程式了。我展開 Client 專案,加入對 Interface 和 Implementation 的參考。然後在主程式中加入以下的敘述 (當然要記得匯入必要的命名空間):

所以我們會透過 MessageReceiver 類別傳回 Message 屬性的值做為要處理的訊息。完成了這個簡單的例子之後,我們就要把實做的成果和要求的模型結合在一起,看看我們的設計是否吻合架構面的要求。要把實做的專案和 Layer Diagram 中定義的層次相結合,方法很簡單。回到 FundamentalLayer 層次圖,然後從 solution explorer 中拖放 Client 專案節點到層次圖的 Client 層次上。此時會看到層次圖形的左上方出現個 1,代表它已經和一個專案綁定了。同樣的方式,把 Interface 專案對映到 Interface 層次,Implementation 專案對映到 Implementation 層次。如果你選擇其中一個已經綁定的層次,可以在 Layer Explorer (如果看不到可以從 Architecre 選單的 Window 命令中找到 Layer Explorer 把視窗調出來) 看到所綁定對象的細節。

有了專案和層次的對映後,接下來就有趣了。我們可以用滑鼠右鍵點選層次圖的表面,會看到快速選單中有一個 Validate Architecture 命令,我們執行這個命令;


進行架構驗證

命令執行完成後會看到錯誤訊息,同時指示錯誤發生的區域。檢視一下錯誤內容,會發現我們要求的層次依賴關係被破壞了,因為 Client 直接呼叫了 Implementation 的設計 (包括參照到 Implementation 專案,以及直接使用 MessageReceiver 類別:


驗證後的錯誤

解決之道是利用 Factory 樣式,利用 Factory 建立以介面為主的方法,隔離實做和介面的關係。所以日後要傳回的訊息接收器是針對不同的訊息來源進行處理,我們只要調整 Factory 方法,傳回對應的接收器,原本的應用程式不用更動,因為它都是透過介面決定作業,只要實做了同樣介面的類別都可以套用,增加程式的彈性和維護能力。所以我們展開 Creator 專案,加入對 Interface 和 Implementation 的參考,然後把 Class1 的名稱改成 MessageCreator。它的程式內容如下:


MessageCreator 類別

緊接著我們移除掉Client專案中原本對 Implementation 專案的參考,然後加入對 Creator 專案的參考。並且更進一步的把原本的主程式更改為:

這樣我們就不是直接透過實做的類別進行訊息的存取,而是經由 Factory 取得符合介面定義的內容。這回我們再做一個層次驗證,可以看到成功通過設計。在這裡用的是一個很小的例子,碰到大型的專案,還是可以透過相同的方式進行驗證。確保我們的程式在架構層次面是遵循要求的。