很高興又一次開始談軟體的架構了,不過這個的探討與09年初寫的淺談MIS系統架構不一樣,之前是理論,現在是實踐,而且這次在實際項目中把之前的理論都實現了,有過之而無不及,驗證和許可權、各層之間的低耦合、不再需要托控制項,等等都實現了,其實一切能夠實現得益於這次架構的魂——一切資料都會經過架構的程式(我們有時叫底層,下面統一叫軟體架構)。遺憾的是這次仍然是一個WinForm項目,如果是web開發那麼其中的很多細節問題都需要從新思考,畢竟運行機制不同嘛。不過這個軟體是一個非常成功的軟體,而且實現了多語言、多單位和多幣種等。
上面所說的各層之間的耦合、不再需要托控制項等(其實還有很多)這些挺表面的東西可能大家並不以為然,那從架構的角度來看下這個問題。
1.這是一個什麼樣的架構,為什麼要這樣架構
之前看到高煥堂大師的《Android應用程式框架原理與程式開發》這本書,書的第二章《應用架構魅力的泉源:反向溝通》,當我第一眼看到“反向溝通”這個詞,我感到作者是我的知音,當然,當我看完這章後我就成了作者的知音,因為作者把什麼是“反向溝通”和為什麼要“反向溝通”這個原理表達的很精準。
我常思考一個問題,那就是所謂的“三層架構”或者“多層架構”中如果實現展示層和業務層之間的低耦合,如果任由開發人員自己托控制項,那麼軟體架構很難控制到它,雖然可以獲得它,但在什麼時候獲得和這個控制項是什麼作用等都是軟體架構無法決定的,無論是winform還是webform都是事件驅動式運行,開發人員會使用控制項的那些事件和事件方法裡寫什麼都是未知的,這樣就可能會出現大量的代碼冗餘和層與層之間的高耦合,還有維護很不方便,同時這樣也是一件浪費時間的工作。
要想解決這些問題,那首先就得讓軟體架構去完成大部分工作,當然是與實際業務無關的工作。如果我們有一個儲存按鈕,我希望當點擊這個儲存按鈕時軟體架構自動調用業務對象中的儲存方法,而不需要實際業務表單去添加事件和寫調用的方法,這就出現了兩個問題,一個是軟體架構如何知道當前需要調用哪個業務對象中的儲存方法,這個很簡單,只要業務對象都有一個基類,然後實現各介面(如:ISavable),軟體架構自己去調用相應介面方法;還有一個問題是要儲存的資料在哪裡?看來軟體架構需要保持有資料實體的引用才行。
正如前面所說:一切資料(廣義上的資料)都會經過軟體架構。所以我的做法是:把需要用到對象都在軟體架構的相應類裡聲明,像業務對象會在展示層的基類裡聲明,每一個表單都有資料,這個資料也在展示層的基類裡聲明,等等(事實上在軟體架構裡聲明的各屬性很多,總共有十幾個吧),開發人員需要給展示層基類的業務對象這個屬性賦值,而資料則不需要去賦值,軟體架構會自己去調用業務對象屬性的查詢資料的介面方法獲得資料。
這樣一來軟體架構中還剩一個問題就是表單上的控制項如何在軟體架構中聲明?因為只有軟體架構保持對表單上控制項的引用才可以用統一的方法進行資料繫結、可見和可用許可權、驗證以及它們所需要的事件,這就需要軟體架構自己去建立控制項,至於實際業務表單顯示哪些控制項是由實際業務表單向軟體架構定製的(這個定製比較複雜,我把這塊單獨抽出來作為一個業務外觀層,通過它能定製控制項以及控制項行為,後面會詳細說它)。
可見:不再托控制項不僅僅是目的還是實現這種架構思路的手段。
正因為一切資料(廣義上的資料)都會經過軟體架構,軟體架構才能控制一切,“反向溝通”才能好好的工作。
2.基本原理
這裡我將軟體中會出現的表單歸了個類,每一種負責一種布局(表單只負責布局,內部的控制項等等由業務外觀層去完成),比如帶樹的列表表單(就是左邊會顯示一個樹列表,右邊一個Gridview的列表,樹列表中的節點改變,Gridview列表的資料發生改變),這些表單都繼承自一個包含業務外觀屬性和一些方法的常用表單類。實際業務表單根據它的業務需要繼承某一種布局的表單,它還要使用業務外觀層中的類建立表單各個布局地區中的內容(很多控制項),並給這些內容指定一個必選屬性“欄位名”(業務外觀運行時會用這個“欄位名”去綁定資料,並可以用這個“欄位名”去索引到這個控制項)和其他一些可選屬性用來定製控制項的內容、行為和樣式等。
這樣一來,業務外觀層是重中之重,它負責介面的繪製、絕大部分互動的調度以及幾乎所有的非功能需求(比如:重新整理後焦點行定位問題)。下面是個草圖,業務外觀層簡單的畫了下(因為下一篇會著重講它),為了簡單說明問題,也只放了一個用於業務的介面ISelectable,事實上是有很多的,比如儲存等,業務外觀層依賴於所有的這些介面以完成介面的操作,而開發人員在寫實際業務表單代碼中不需要主動調用業務對象或者介面。
如果換個角度去看,業務外觀層不僅僅是上述作用,它是對平台(.NET)和組件的一層抽象,以另一種方式讓開發人員編程,它還有它自己的運行機制。它還拋棄了以往拖拖拽拽操作麻煩、修改維護不方便(需要在設計器中設定,而現在可能只是移動上下行代碼)、表單風格不統一,同時它還屏蔽了第三方組件的使用(如果項目中用了第三方組件,但團隊中不一定是每個人都很熟練的使用這套組件,那麼這個方案能給大家節省很多時間)。
3.總結
常用表單為各種布局的表單的基表單,它聲明了業務外觀屬性,子類可以訪問業務外觀屬性並設定自己的外觀。
從常用表單派生的表單只負責布局,布局中的每一塊稱為地區,地區中的所有控制項都是由業務外觀層根據業務外觀屬性建立的。
業務外觀層根據實際表單中定製的操作建立事件和綁定對應的事件方法完成與業務對象的互動。
與業務對象的互動都是使用介面完成的,一個業務對象實現了某個介面就表示它擁有這樣的能力,比如ISavable介面,就表示這個業務對象是可以儲存的,所以我們定義了很多介面。
下一篇講解釋業務外觀層的設計和許可權與驗證的設計。