軟體項目實訓及課程設計指導——如何保證軟體應用系統架構設計結果的可擴展性和可重用性(上篇)
1、良好的可重用性軟體系統架構設計結果的主要體現
可重用性的軟體應用系統的系統架構設計結果主要體現在如下兩個方面——本項目的系統架構設計的結果是可重用的和在本項目的系統架構設計中重用成熟的系統架構設計方案。
當然,要能夠達到這樣的軟體系統架構設計結果,需要設計人員充分地應用面向對象技術中的抽象機制,對軟體應用系統中共性的部分進行充分的抽取。
而為了能夠保證軟體應用系統的系統架構設計結果是可擴展的,必須要應用「封裝」和「隔離」的設計手段、並且遵守一些相關的設計原則和應用典型的設計模式。
作者在下文將為讀者詳細介紹如何保證軟體應用系統的系統架構設計結果具有良好的可擴展性和可重用性。
2、軟體應用系統在縱向結構方面需要進行分層和隔離
(1)縱向分層和隔離
「層(Layer)」在面向對象的系統設計中是指對軟體應用系統中的功能模塊和類、或子系統等粗粒度的分組機制,每一層具有相對獨立和內聚的職責——各層之間的依賴關係應該是逐層向下而不能跨層產生依賴關係;而且只能是上層依賴於下層、而不能讓下層反過來依賴於上層。
比如,本系列文章中所給出的示例項目——銀行帳戶信息管理系統項目在縱向分層隔離方面採用四層次的系統架構設計,下圖所示中的UML包圖為體現本軟體應用系統項目的系統架構設計結果的分層包圖。
示例UML包圖中所示的系統分層設計完全遵守依賴倒置原則——依賴倒置原則的本質就是要求將軟體應用系統的架構設計中的各個層之間的關係要建立在依賴抽象接口的基礎上,同時要求上層模塊不應該直接依賴於下層的模塊,它們兩者都共同依賴於一個抽象;抽象元素不能依賴於具體元素,而具體元素則必須依賴於抽象元素。
(2)合理地對軟體應用系統在縱向方向進行分層隔離設計
通過合理地對軟體應用系統在縱向方向進行分層隔離設計——如目前的C/S和B/S等架構模式中的各個分層策略,將允許設計人員將複雜的軟體應用系統中所涉及的各個方面的問題分解成多個不同層次的實現。每一層最多只影響其相關聯的上、下兩層,同時只要給相鄰的上、下層提供接口或者實現接口,從而也就能夠允許每層使用不同的方法包括不同的技術來實現,因此為軟體應用系統的可重用提供了強大的結構支持。
經典的三層架構的系統設計——即自底向上依次是數據訪問層、業務邏輯層和表示層,而MVC架構模式是對它的進一步完善;下圖所示的J2EE Web系統平臺中的四層架構設計(表示層、控制層、業務邏輯層和數據訪問層)能夠保證軟體應用系統架構設計的結果是可重用的。
當然,為了進一步分離系統中的業務處理層和持久層之間的依賴耦合關係,也可以在系統的業務處理層和持久層之間插入一個數據服務層(一般應用於採用J2EE EJB分布式的數據訪問和存儲的應用系統的系統架構設計中)。如下示圖為J2EE EJB系統平臺中的五層架構設計示例圖,同樣也都能夠保證軟體應用系統架構設計的結果是可重用的。
(3)層與層之間應該要相互分離
在軟體應用系統的多層架構設計中,一般都倡導將軟體應用系統中的界面顯示功能、業務邏輯處理功能和數據訪問功能完全分離(但按照MVC架構模式的劃分規則,在軟體應用系統的系統架構設計中的業務邏輯層以及數據訪問層中的各個組件都屬於MVC架構模式中的模型組件),而不要在軟體應用系統的界面組件(一般處於系統的表示層)中加入應用邏輯功能實現,從而避免了在應用系統的需求發生變化時(功能方面或者非功能方面),而產生牽一髮而動全身的連鎖修改軟體應用系統的設計方案和功能實現的代碼,可以實現軟體應用系統的鬆耦合和良好的系統可維護性。
如下示圖為某個Web應用系統中的Web頁面實現的代碼局部截圖--HTML標籤和Java處理邏輯代碼混雜在一起。這樣的代碼設計導致表示層和業務邏輯處理層相關的程序代碼緊密耦合,其中的業務邏輯處理的程序代碼也是不可重用的——因為其中的某些功能模塊很難在別的軟體應用系統中被重新使用,因為不能將它從現有的軟體應用系統中獨立地提取出來——在Java程序代碼中混雜有HTML標籤,產生類似「拔出蘿蔔帶出泥」的狀況!
3、軟體應用系統在橫向結構方面也需要拆分為不同的功能模塊
(1)橫向拆分為不同的功能模塊
軟體應用系統的系統架構設計師為了能夠分離各個模塊之間的藕合度,應該要對軟體應用系統的橫向結構也進行拆分為不同的功能模塊。但設計人員如何能夠獲得低藕合的模塊設計結果?
常用的設計策略是遵守面向對象設計中所倡導的依賴倒置原則、並應用控制反轉和依賴注入技術(IOC,Inversion of Control)。下圖所示為某個字符轉換小系統的橫向分塊設計結果的UML組件圖的局部截圖。
(2)模塊之間依賴關係應該要儘可能達到低藕合的模塊設計目標
應用面向對象設計中所倡導的依賴倒置原則實現將依賴關係倒置為依賴接口,從而在很大程度上阻止了「由於需求發生變化而導致代碼修改」的變化波及範圍的擴大,有效地隔離了「變化」和有助於增強軟體應用系統的可重用性和可擴展性。
利用控制反轉技術能夠消解框架系統和軟體應用系統之間的依賴關係——因為利用「控制反轉」技術能夠減少對象的請求者對服務提供者的特定功能實現邏輯的依賴,此時系統中的各個組件類不再需要自己去查找或者實例化它們所依賴的其它目標組件類的對象實例。
如下示圖所示,在Struts 2框架中由於應用了ActionProxy代理,從而隔離軟體應用系統中的各種業務處理的Action組件對Servlet容器的依賴,並且Struts 2框架中的Action組件類無須繼承Struts2框架中的任何基類或實現任何的接口,為純的POJO。
而在早期的Struts框架中,由於承擔系統業務處理功能的Action組件直接繼承於Struts框架系統的ActionServlet組件(示例圖中的上圖),從而導致系統業務處理功能的Action組件緊密耦合Struts框架系統。
利用依賴注入消除軟體應用系統中的各個對象在創建時所產生的依賴藕合關係,在橫向分塊設計中儘管遵守了依賴倒置原則,也只能夠隔離對象的使用者和對象功能的實現者之間的依賴關係。但在創建具體實現類的對象實例時,仍會造成對於具體功能實現類的直接依賴。而採用依賴注入技術則可以消除這種在對象創建方面所產生的依賴性,如下示圖所示在Struts 2框架中應用struts.xml配置文件實現對軟體應用系統中的各個Action類的對象實例進行定義,而不是直接在程序代碼中創建出對象實例。
(3)通過不斷地進行設計重構過程逐步完善系統架構設計的設計結果
當然,軟體應用系統的設計人員在進行橫向分塊設計時,應該要儘可能減少各個模塊之間的相互關係、特別是要避免出現「多對多」的依賴關係。從上圖所示的組件圖中,讀者應該可以發現出該軟體應用系統中的各個功能組件之間的關係是比較複雜的!
其中軟體應用系統中的業務層(用戶信息管理、各種形式的字符轉換功能管理等)與軟體應用系統中的持久層之間存在「多對多」的關係、並且軟體應用系統中的業務層中的各個組件緊密依賴於持久層中的組件具體技術實現方式。
因此,對軟體應用系統中橫向分模塊設計需要不斷地進行系統重構,也就是在軟體應用系統的「持久層」和「業務層」之間可以增加一個「數據服務層」,從而隔離「業務層」對「持久層」的過分的依賴,並且可以在軟體應用系統中的「持久層」的具體技術實現發生變化時,不會影響到軟體應用系統中的「業務層」的功能實現。
該軟體應用系統重構後的各個組件模塊的UML組件圖請見下圖所示,最終解除了軟體應用系統中的業務層與持久層之間的「多對多」的關係!軟體應用系統中的各個組件模塊之間的關係都簡化為「單一關係」、而且高層組件只依賴於底層的組件——遵守了面向對象設計中的依賴倒置原則!