面向模式構建軟件系統架構

       架構是一個軟件系統中的核心元素,是系統中最難改變的部分,也是構建軟件系統中其他部分所依賴的基礎,因此係統架構的好壞會從根本上決定基於這個架構所構建的軟件系統的質量。系統架構的構建一直是軟件開發過程中的一項重要工作,同時也是一項很困難的工作,即便對於很有經驗的系統架構師也是如此。但是,模式以及模式語言的提出給出了一條構建系統架構的有效途徑,本文將對此進行深入的論述,並以一個著名的單元測試工具JUnit爲例進行說明。
概念分析

首先,對架構(architecture)和模式(pattern)這兩個概念進行簡單的介紹。前面已經講過,架構是一個系統中的核心元素,是該系統中最本質的部分。系統的各個組成部分正是通過架構所描繪的方式協同工作共同完成系統的功能,從而表現出一個完整的系統。

        什麼是模式呢?模式是在某種特定的場景(context)下某個不斷重複出現的問題的解決方案。模式本身並沒有任何的創新性,它僅僅是對於一些已經被證明爲優秀的解決方法的歸類、總結,目的是爲了重用該解決方案而又不用做重複的勞動。其中,"特定場景"和"重複"兩個限定詞非常關鍵,"特定場景"給出了什麼時候以及爲什麼使用一個模式,"重複"說明了模式的可重複性從而可以被重用。參考文獻〔4〕中總結了23個經典模式,非常值得讀者朋友細心研讀。

架構搭建的難點

既然架構是一個系統中最核心、最本質的部分,要想構建一個正確的架構當然不會容易,爲什麼呢?下面將從幾個方面進行分析。

首先,由於架構是一個系統中的本質的反映,因此架構一般是由系統中不容易改變的部分組成,這些不容易改變的部分往往是系統中的一些抽象的概念。但是,我們在構建系統的架構前僅僅有一些用戶的需求以及對於用戶業務流程的用例(use case),如果缺乏有效的指導原則,很難從這些信息中提取出反映問題領域本質的概念來。關於這一點,參考文獻3中給出了一個很有效的方法:Commonality/Variability(公共性/可變性)分析。它的核心思想是針對問題領域中的概念進行分類,把那些看上去不同但本質上屬於一類的概念用一個抽象的概念來表示,然後基於這些抽象的概念構建架構。Commonality/Variability分析方法在發現系統中的抽象概念方面確實很有效,但是前面已經說過,系統架構不僅僅是一些系統中的抽象概念,而且還描繪了這些抽象概念間的關係,僅僅使用Commonality/Variability分析方法不能十分有效的發現抽象概念間的關係。

其次,即使確定了抽象概念間的關係,構建起了一個系統架構,在這個架構的指引下,我們還是很有可能陷入困境。爲什麼呢?因爲該架構可能會缺乏對於我們進一步工作的指引,缺乏後續發現對象的有效手段。也就是說,架構可能過於空泛,缺乏延伸性。

最後,一個經驗豐富的系統架構師可能成功的構建了一個系統的架構,成功的基於該架構完成了系統,但是他的經驗、心得體會可能會很難爲其他的系統架構師所理解,從而在解決同類問題時可以有效的被重用。因爲,這些心得體會如果表現的過於抽象,可能會顯的空泛從而指導意義不大;如果表現的過於具體,有可能陷入細節從而失去通用性。

正是由於上述原因使得系統架構的構建非常的困難,往往必須由資深的系統架構師來完成。但是隨着模式的提出以及對模式研究的深入,這種局面正在逐步的改變。下面讓我們先來對模式進行一番深入的認識。

深入認識模式

讀者對於模式的認識大都是從《設計模式》(由參考文獻[4]翻譯而來的)一書的出版開始的。該書中描繪了23個經典的模式,每一個模式都給出了一個精製優雅的解決方案,爲每一個程序員所沉迷、拍案叫絕。但是由於經驗的不足往往會造成對於模式的誤解。《設計模式》一書的作者John Vlissides爲此專門寫了一片文章進行闡述,詳見:http://www.research.ibm.com/designpatterns/pubs/top10misc.pdf。本人在對模式進行深入的研究以及實踐的基礎上,把對於模式的認識劃分爲三種境界,下面一一進行說明。

第一層境界:認爲模式就是一種解決方案,一般剛剛接觸模式的人都處於這個認識層面。確實是這樣,剛剛見到模式時很容易被它所提供的精製的解決方案所吸引,由於缺少經驗反而容易忽略模式的其它的重要方面。這樣做非常容易造成對於模式的誤解、誤用。比如:爲了使用模式而使用模式以及過分的使用模式等。這種境界僅僅認識到模式怎樣(How)去解決一個問題。

第二層境界:除了解模式提供的解決方案以外,還能夠認識到模式背後的一些指導原則。《設計模式》一書的第一章對於模式背後的一些指導原則進行了詳細的論述,比如:針對接口編程;優先使用組合而不是繼承;發現變化、封裝變化等。不過缺乏經驗的人可能對此理解不會深刻,甚至忽略了這些原則,需要不斷的實踐、體會方能理解。不過體會到這些原則之後就會對面向對象的思想的理解提升一個層次,提高自己的面向對象分析、設計能力。參考文獻2中對於這些原則有深入細緻的講解,相信會對讀者有非常大的幫助。

第三層境界:認識到模式其實是一些關係,用來舒緩系統內部的"衝突力"。這一點僅僅從模式提供的解決方案實例中就可以看出。其實,不管你如何去做,最終的解決方案肯定是一些模塊通過彼此的交互、建立一種關係來完成所需的功能。爲什麼模式提出的方法就是好的呢?就是因爲模式給出的關係舒緩了系統內部的"衝突力",使人感受上去舒服一些。另外,模式並不是簡單的給出了一些概念間的關係,它進一步爲我們提供了一個場景,提供了進一步工作的指導。是不是太抽象了,我們來舉一個例子來說明一下:面向對象設計中有一個著名的原則:SRP(Single Responsibility Principle),即一個類僅僅需要一個職責。如果一個類有多於一個的職責有問題嗎?實現起來當然沒有問題,但是經驗豐富者馬上就會感覺到職責間關係的這種"衝突力",從而感覺到不舒服。反映到實現層面上就是本來毫無關係的模塊間依賴過於強,導致代碼僵化,牽一髮而動全身。"高內聚,松耦合"堪稱軟件領域處理模塊間關係的首要指導原則,但是它沒有告訴我們對於一個問題具體該如何去做,模式的出現填充了這個空白,如果我們知道一個模式可以解決我們手頭的問題,那麼我們就可以非常感性的認識到如何達到"高內聚,松耦合",因爲模式已經給出了這些關係。這一層境界非常抽象,很難達到,有興趣的讀者可以閱讀參考文獻[1],相信會有更進一步的認識,更加深入的理解。

下面我們就來談談模式爲什麼能夠爲系統架構的構建帶來有效的幫助。

面向模式構建系統架構

前面介紹了構建系統架構時的難點,本小節將講述一下模式如何能夠有效的解決這些難題,使得系統架構的構建變得有章可循。

前面曾經提到過,Commonality/Variability分析方法可以有效的發現反映問題領域本質的概念,但是不能十分有效的發現抽象概念間的關係。如果Commonality/Variability分析方法和模式結合起來,就能夠有效的解決這個問題。上一小節也說過,模式其實就是一些關係。如果我們有一些需求,並且我們知道有針對該需求的模式,那麼我們就可以通過Commonality/Variability分析方法發現反映問題領域本質的概念,然後根據可用的模式去建立這些概念之間的關係來實現我們的需求。這樣我們就可以通過模式有效的克服不能有效確定概念間關係的難點。

模式本身並不僅僅簡單是一些關係,它還具有深刻的內涵。它具有自身的意圖、動機、適用性以及核心解決方案等衆多的內容。一旦我們確定使用了一個模式,那麼這個模式就爲我們搭建了一個內容豐富的場景,這個場景可以非常有效的指導我們進一步的工作,啓發我們發現新的對象。這樣,基於模式構建的系統架構就變得抽象(模式本身就是一些抽象的關係)而不空泛並且具有很好的延伸性。

模式也提供了一套公認非常有效的記錄方法,可以把自己經過反覆驗證的解決方案記錄下來傳授給其他人重用,即模式具有可傳授性。這樣,有經驗的系統架構師就可以把自己的一些心得體會通過模式的方法記錄下來,就可以克服經驗無法有效傳授的問題。

其實很多模式本身就是針對系統架構提出的,比如:MVC(Model-View-Controller),它是專門針對交互系統提出的,所以如果我們要構建一個交互系統,那麼我們就可以直接應用MVC模式,然後在該模式所搭建的場景的啓發下去發現Model、View以及Controller,在這個大的場景的指導下根據其它的需求(模式)構建一些小的場景對系統進行有效的分化。細心的讀者會發現,模式和系統架構有很大的相似性,都是處理一些抽象概念間的關係,但是二者還是有很大的不同的,模式是領域無關的,它是解決一些抽象問題的,但是系統架構是針對我們要解決的實際問題的,是領域相關的。我們可以通過對問題領域的分析、分解,找到和我們要解決的問題匹配的模式,對該模式進行定製應用到我們的系統中來。把模式結合在一起構建起整個系統架構來。

面向模式構建的系統架構在需求發生變化時還會使我們處於一個非常有利的位置。爲什麼呢?因爲模式是針對一個反覆出現的問題的優秀的解決方案,它的方法就是發現變化、封裝變化。它本身已經充分考慮了變化的情況。模式採用了一種不同的對待變化的方法,它不是預先考慮會如何變化,而是考慮哪裏可能會變化,然後隔離,所以當變化發生時我們就處於一個有利的位置上。

最後讓我們來看看模式論壇研究、探討的一個焦點論題:模式的生成性。模式的生成能力是指模式創建最終行爲的能力。有人認爲,模式系統可以形成一種語言,即模式語言。模式既是模式語言的要素,同時又是模式語言的規則。象數學證明一樣,可以通過模式的推導、演繹生成系統架構。當然,目前的模式語言遠遠還不完備,還不具有如此強大的生成能力。不過,至少爲我們的軟件開發的永恆解決方法提出了一個美好的希望,讓我們大家共同來爲此努力。有興趣的讀者可以到hillside.net獲得更多有關模式語言的信息。

JUnit架構一覽

前面講了這麼多,本小節我們將結合一個實例進行說明。我所選擇的是JUnit,一個很著名的單元測試工具,選擇它作爲例子主要有兩個原因:其一是JUnit相對比較簡單,這樣我可以集中於要論述的主題;其二是JUnit中大量使用了模式,這樣大家可以對於上面的論述有一個感性的認識。下面對於JUnit的說明會比較粗略,讀者可以到www.junit.org去了解有關JUnit的更加詳細的信息。

JUnit是一個單元測試工具,所以它就要滿足使用者對於單元測試工具的需求。讓我們一一來進行說明,首先測試用例的書寫必須要容易,只有這樣大家纔可能會使用該測試工具。要迎合這一點,我們可以通過把測試用例表示爲對象的方式來完成,對象的概念和人思維中的概念最爲貼近,表示起來也最爲自然。Command非常符合我們的要求,看看它的意圖:將一個請求封裝成一個對象,從而對請求進行排隊或者記錄日誌…。另外,測試工具要爲使用者做它能夠做的最多的事情,儘量減少使用者的工作量,我們必須對測試的一般流程進行分析,歸納出一個模板流程,這樣就可以使使用者僅僅關注自己所需要的具體步驟而不用考慮如何去組織這些步驟(一般的測試都分爲測試準備即setUp,運行測試即runTest以及結束清除即tearDown階段),Template Method模式正好能夠幫上忙。另外,測試工具應該能夠統一處理單獨的用例以及多個用例的組合,這樣也可以大大減少使用者的工作量,是不是馬上就想到了Composite模式,不錯,就是它。

下面根據上面的論述,在我們所得出的模式場景的指導下,給出JUnit系統架構的UML圖表示:


 
 

Junit本身提供了源代碼,有興趣的讀者朋友可以參閱。不過如果瞭解了系統的架構後在去看源代碼的話,相信會有不同的感受。
結論

本文從宏觀上探討了系統架構、模式以及模式在構建系統架構方面的的有效性。限於篇幅,其中有很多重要的內容沒有做十分深入的論述,關於這些內容準備在後續的文章中作爲獨立的主題來講解。希望本文能爲讀者朋友帶來一些啓發。最後我就以模式的提出者Christopher Alexander的一段具有深刻內涵的話作爲結束:"以一種鬆散的方式把一些模式串接起來建造建築是可能的。這樣的建築僅僅是一些模式的堆砌,而不緊湊,這不夠深刻。然而另有一種組合模式的方式,許多模式重疊在一個物理空間裏,這樣的建築非常緊湊,在一小塊空間裏集成了許多的內涵,由於這種緊湊,它變得深刻。" 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章