以下是Garlan和Shaw對常見建築風格的分類:
(1)數據流樣式:批處理序列;管道/過濾器
(2)調用/返回方式:主程序/子程序;面向對象的風格;分級結構
(3)獨立組件風格:進程通信;事件系統
(4)虛擬機風格:解釋器;基於規則的系統
(5)倉庫式:數據庫系統;超文本系統;黑板系統
限於篇幅,本文只介紹幾種主要的、經典的建築風格及其優缺點。新興的軟件架構風格將在後續文章中介紹。C2架構風格可以概括為:由連接器綁定在壹起的並行組件網絡,並根據壹組規則進行操作。C2風格的系統組織規則如下:
(1)系統中的組件和連接器有頂部和底部;
(2)組件的頂部應連接到壹個連接器的底部,組件的底部應連接到壹個連接器的頂部,不允許組件之間直接連接;(3)壹個連接器可以與任意數量的其他部件和連接器連接;
(4)當兩個連接器直接連接時,它們必須從壹個的底部到另壹個的頂部。
圖3是C2風格的示意圖。圖中組件和連接器之間的連接體現了以C2風格構建系統的規則。
圖3 C2風格建築
C2風格是最常用的軟件架構風格。從C2風格的組織規則和結構圖中,我們可以得出以下結論:
(1)系統中的組件可以滿足應用需求,並且可以封裝任何復雜度的功能。
(2)所有組件之間的通信通過以連接器為中介的異步消息交換機制來實現;
(3)組件相對獨立,組件之間依賴較少。系統中沒有相關假設,即壹些組件將在相同的地址空間中執行,或者壹些組件* * *共享特定的控制線。在管道/過濾器風格的軟件架構中,每個組件都有壹組輸入和輸出。該組件讀取輸入數據流,在內部對其進行處理,然後生成輸出數據流。這個過程通常是通過輸入流的變換和增量計算來完成的,所以輸出是在輸入被完全消耗掉之前產生的。所以這裏的組件叫做過濾器,這種風格的連接器就像是壹個數據流傳輸的管道,把壹個過濾器的輸出傳輸到另壹個過濾器的輸入。壹個特別重要樣式的過濾器必須是壹個獨立的實體,不能和其他過濾器共享數據,壹個過濾器不知道自己的上下遊身份。管道/過濾器網絡輸出的正確性不取決於過濾器執行增量計算的順序。
圖4是管道/過濾器類型的示意圖。管道/過濾器架構的壹個典型例子是用Unix shell編寫的程序。Unix不僅提供了壹個符號來連接組件(Unix進程),還提供了壹些進程運行時機制來實現管道。另壹個著名的例子是傳統的編譯器。傳統的編譯器壹直被認為是壹個流水線系統,其中壹個階段的輸出(包括詞法分析、語法分析、語義分析和代碼生成)是另壹個階段的輸入。
圖4管道/過濾器風格的架構
管道/過濾器風格的軟件架構有許多好的特性:
(1)使軟構件具有良好的隱蔽性、高內聚性和低耦合性;
(2)允許設計者將整個系統的輸入/輸出行為視為多個濾波器行為的簡單合成;
(3)支持軟件復用。重要的是提供適合在兩個過濾器之間傳輸的數據,並且任何兩個過濾器都可以連接;
(4)維護和增強系統性能簡單。新的過濾器可以添加到現有的系統中;舊的可以用改進的過濾器代替;
(5)允許分析壹些屬性,例如吞吐量和死鎖;
(6)支持並行執行。每個篩選器都作為壹個單獨的任務完成,因此它可以與其他任務並行執行。
然而,這種系統也有壹些缺點。
(1)通常會導致壹個進程成為批處理結構。這是因為雖然過濾器可以增量處理數據,但它們是獨立的,因此設計人員必須將每個過濾器視為從輸入到輸出的完整轉換。
(2)不適合交互式應用。當需要增量顯示更改時,這個問題尤其嚴重。
(3)由於數據傳輸沒有統壹的標準,每個過濾器都增加了解析和合成數據的工作,導致系統性能下降,增加了編寫過濾器的復雜度。抽象數據類型概念在軟件系統中起著重要的作用。目前,軟件行業已經普遍轉向面向對象系統。這種風格基於數據抽象和面向對象,數據表示方法及其相應的操作封裝在壹個抽象的數據類型或對象中。這種風格的組成部分是抽象數據類型的對象或實例。對象是壹個被稱為管理器的組件,因為它負責維護資源的完整性。對象通過調用函數和過程進行交互。
圖5是數據抽象和面向對象風格的示意圖。圖5數據抽象和面向對象風格的架構
面向對象系統有許多優點,而且早已為人所知:
(1)因為壹個對象對其他對象隱藏了它的表示,所以可以更改壹個對象的表示而不影響其他對象。
(2)設計者可以將壹些數據訪問操作的問題分解成壹組交互式的代理程序。
然而,面向對象的系統也有壹些問題:
(1)為了使壹個對象通過過程調用與另壹個對象進行交互,需要知道對象的標識。每當壹個對象的標識改變時,所有其他顯式調用它的對象都必須被修改。
(2)必須修改所有其他顯式調用它的對象,並且必須消除由它引起的壹些副作用。例如,如果A使用對象B,C也使用對象B,那麽C使用B對A的影響可能是意想不到的。基於事件的隱式調用風格的思想是組件不直接調用壹個過程,而是觸發或廣播壹個或多個事件。系統中其他組件的進程在壹個或多個事件中註冊。當壹個事件被觸發時,系統自動調用該事件中註冊的所有進程,這樣壹個事件的觸發導致另壹個模塊中進程的調用。
從體系結構上來說,這種風格的組件是模塊,它可以是過程,也可以是事件的集合。可以用壹般的方式調用過程,也可以在系統事件中註冊壹些過程,當這些事件發生時,調用過程。
基於事件的隱式調用風格的主要特點是事件的觸發器不知道哪些組件會受到這些事件的影響。這樣我們就無法假設組件的處理順序,甚至無法知道會調用哪些過程。因此,許多隱式調用的系統也包含顯式調用,作為組件交互的補充形式。
有許多應用系統支持基於事件的隱式調用。比如用來集成編程環境中的各種工具,保證數據庫管理系統中數據的壹致性約束,管理用戶界面系統中的數據,支持編輯器中的語法檢查等。例如,在某個系統中,編輯器和變量監視器可以註冊相應調試器的斷點事件。當調試器在斷點處停止時,它聲明事件,系統自動調用處理程序。例如,編輯器可以滾動到斷點,變量監視器刷新變量值。調試器本身只聲明事件,並不關心哪些進程將啟動或它們做什麽。
隱式調用系統的主要優點是:
(1)為軟件復用提供了強有力的支持。當壹個組件需要添加到壹個現有的系統中時,只需要在系統的事件中註冊它。
(2)為系統的改進帶來了方便。當壹個組件替換另壹個組件時,不會影響其他組件的接口。
隱式調用系統的主要缺點是:
(1)組件放棄對系統計算的控制。當壹個組件觸發壹個事件時,不確定其他組件是否會響應它。即使它知道事件註冊了哪些組件,它也不能保證這些過程的調用順序。
(2)數據交換的問題。有時數據可以通過事件傳遞,但在其他情況下,基於事件的系統必須依賴* * *共享倉庫進行交互。在這些情況下,全局性能和資源管理就成了問題。
(3)由於流程的語義必須依賴於被觸發事件的上下文約束,所以關於正確性的推理存在問題。層級制組織成層級結構,每壹層服務於上層,服務於下層客戶。在壹些分層系統中,除了壹些精心選擇的輸出函數,內層只對相鄰層可見。在這樣的系統中,組件在某些層實現虛擬機(在其他層中,這些層是部分不透明的)。連接器由確定層如何交互的協議定義,拓撲約束包括對相鄰層之間交互的約束。
這種風格支持基於添加抽象層的設計。這樣,壹個復雜的問題可以分解成壹個漸進的步驟序列。因為每壹層最多只影響兩層,而且只要相鄰層提供相同的接口,就允許每壹層以不同的方式實現,這也為軟件復用提供了強有力的支持。
圖6是分級系統風格的示意圖。最廣泛使用的分層系統是分層通信協議。在這個應用領域中,每壹層都提供了壹個抽象函數作為上層通信的基礎。下層定義了下層的交互,最低層通常只定義硬件的物理連接。
圖6分層系統風格的架構
等級制度有許多可取的屬性:
(1)支持基於遞增抽象的系統設計,使設計者能夠以遞增的步驟分解壹個復雜的系統;
(2)支持功能增強,因為每壹層最多與相鄰的上下層交互,所以功能的變化最多影響相鄰的上下層;
(3)支持重用。只要所提供的服務接口定義保持不變,同壹層的不同實現就可以互換使用。這樣就可以定義壹套標準接口,允許各種實現方法。
然而,等級制度也有其缺點:
(1)不是每個系統都可以很容易地劃分成層次模式。即使系統的邏輯結構是分層的,為了系統性能,系統設計者也不得不組合壹些低級或高級功能。
(2)很難找到壹種恰當的、正確的層次抽象方法。在倉庫風格中,有兩個不同的組件:中央數據結構描述當前狀態,獨立組件在中央數據存儲上執行。倉庫和外部組件之間的交互將在系統中發生巨大變化。
控制原理的選擇產生兩個主要的子類。如果輸入流中的某種時間觸發了流程執行的選擇,那麽倉庫就是傳統的數據庫;另壹方面,如果中心數據結構的當前狀態觸發了流程執行的選擇,那麽倉庫就是壹個黑板系統。
圖7是黑板系統的組成。黑板系統的傳統應用是在信號處理領域,如語音和模式識別。另壹個應用是松散耦合的代理數據訪問。
圖7黑板系統的組成
從圖4中我們可以看到,黑板系統主要由三部分組成:
(1)知識來源。知識源包含獨立的和應用相關的知識,知識源之間沒有直接的交流,它們之間的交互只是通過黑板來完成。
(2)黑板數據結構。黑板數據是按照與應用相關的層次組織起來的解題數據,知識源通過不斷改變黑板數據來解題。
(3)控制。控制完全由黑板的狀態驅動,黑板狀態的變化決定了使用的具體知識。