天天看點

J2EE應用系統的MDPB開發方法

摘要:本文介紹了一種适用于面向對象的J2EE應用系統的開發方法,其核心思想是MDPB-Model Driven Pattern Based即基于藍圖的模型驅動設計。

概述

一般的軟體的分析設計過程為:需求調研,需求分析,概要(架構)設計,資料庫設計,詳細設計,而面向對象的分析設計方法有很多種,其中RUP堪稱集大成者,但是RUP的分析設計過程過于複雜。現實中很少有項目能夠完整的遵循UML模組化過程執行的,從設計用例圖、強固圖、時序圖、類圖,一直到部署圖一步步的進行推導。絕大部分項目隻使用了常用的UML圖,例如類圖,時序圖,用例圖,而在後續的設計開發過程中,幾乎完全将之擱在一邊,這些圖僅起參考啟發的作用。ICONIX方法對RUP進行了提煉和簡化,但是仍然顯得步驟繁瑣,缺乏切實可行的步驟。

在面向對象WEB應用系統的軟體分析和設計過程如何具體操作,至今沒有一種很好的實踐方法。有鑒于此,筆者通過幾個項目的實踐,總結出一種更加簡便的分析設計過程,能夠很好的适用于面向對象的J2EE WEB應用系統的開發,也同樣适用于富用戶端應用系統的開發。

這個過程依據通用的需求調研、需求分析、架構設計、詳細設計到編碼實作的5個步驟,描述了針對一個J2EE WEB應用系統,每個步驟的工作如何具體開展,重點在于如何依據架構模式從領域模型推導出業務邏輯層的代碼,其思想的核心是MDPB-Model Driven Pattern Based基于架構模式的模型驅動設計。

需求調研

需求可以劃分為2個層次:業務級需求和軟體實作級需求。

需求調研主要目的是獲得使用者的業務需求,可以使用業務流程圖來表述。業務流程圖從使用者的角度描述了真實完整的業務過程business process,其中部分流程可以用軟體實作。業務流程圖是業務級的需求。當然,客戶的期望和業務需求仍然需要用文字進行描述。

繪制業務流程圖

由于業務流程圖與實際業務過程是一緻的,并且使用使用者習慣的專業詞彙,是以需求分析人員和最終使用者可以一起讨論制定,在經過客戶方稽核認可後定稿。業務流程圖可以從整體業務流程圖出發,進行業務劃分,層層分解得到每個子業務的流程圖,是以業務流程圖分為多個層次。

在需求調研階段不可忽視客戶的期望,在英文詞中,需求是REQUIREMENT,而這些期望是NEED,往往也被稱為需求背後的需求,我們要将這些期望記錄下來。

需求分析

需求分析是根據需求調研的結果,包括業務流程圖、規章制度、表格等進行業務領域分析,同時使用用例描述、界面原型、領域模型3種技術進行分析。

用例描述可以記錄業務級需求,也可以記錄軟體實作級需求,通過用例分析可以推導出界面原型和領域模型。

界面原型是軟體的外在表現,展現了使用者與軟體進行互動的過程。一個軟體最終展現給使用者的就是人機互動的界面,人機互動界面就是需求的一種實作,引入界面原型可以在一開始就給使用者一種直覺的感受,“啊,這個軟體是這樣子的,嗯,這是我想要的功能!”。

領域模型使用類圖來表述了一個軟體的靜态結構,是從客觀世界中抽象歸納出來的模型,是軟體實作級的需求。

需求分析的結果是編制出需求規格說明書,将前述的業務流程圖、表格、業務特性、功能需求描述、界面原型、用例描述彙總在一起。另外,需求分析過程中要注意從功能需求中提取出可以作為重用元件的需求。

需求分析涉及的關鍵方法有:領域模型設計、用例分析。

J2EE應用系統的MDPB開發方法

從業務級需求推導出系統實作級需求

用例描述

用例描述使用主成功場景和擴充場景來展現互動過程的。一個場景就如同一個劇本描述了各個演員(actor)的對白和活動,故事情節的發展。

軟體實作級需求分為功能需求和非功能需求(包括性能需求,易用需求,安全需求等)。功能需求描述、非功能需求描述是從應用系統實作的角度描述系統的行為和特性。功能需求分析主要是依據業務子產品劃分出功能子產品,并對每一功能子產品進行表單、屬性、操作的分析。進行功能需求分析時,業務連貫較強的功能子產品可以使用用例分析技術來表述一個軟體的内在動态聯系。用例描述可以作為軟體實作級的需求描述手段。

用例主要使用操作者、主成功場景、擴充場景、前置條件幾個要素描述軟體内在的動态聯系,這種内在關系是界面原型上無法表述的,也避免了對功能子產品分而治之導緻功能之間缺乏連貫。在需求調研時,我們了解到各類使用者的業務活動,但是業務活動之間的聯系缺乏一種清晰完整描述方法,用例分析技術就是為了解決這個問題。

從用例出發,我們可以推導出使用者的界面原型的概貌,人機之間交換資訊的過程,以及整個業務流程中各使用者是如何參與互相配合的。當然,界面設計還要依賴使用者使用的各種表格。

從用例能夠推導出領域模型。例如在用例的場景描述中:使用者送出某個表單後,系統進行檢查并給出一個是否成功的提示。這意味着某個實體上需要送出、檢查的操作。

如何編寫出用例,在《編寫有效用例》一書中有非常詳細的闡述,本文不作贅述。值得注意的是,用例場景的描述文字遠比用例圖重要。

繪制界面原型

根據調研結果,繪制界面原型,可以是HTML,或者visio等。界面原型最好能夠有人機互動過程,使使用者能夠直覺的體驗到自己的需求如何被系統實作。通過界面原型可以探明業務需求的風險,在早期與使用者就需求達成一緻。界面原型的設計可以依據互動式設計的原理進行,這裡不做詳述。

領域模型

什麼是軟體的核心和價值所在?是軟體解決業務領域問題的能力。作為需求分析人員應該關注業務領域。領域模型使需求分析人員将注意力集中在如何解決領域問題,而不涉及技術實作手段,另一方面,可以将需求分析人員的想法傳遞給開發人員進行詳細設計和編碼開發。

建立領域模型

建立領域模型的步驟如下:

1. 根據需求(現實世界)建立詞彙表

2. 從需求和詞彙表中發現名詞和概念,作為業務領域的候選實體類

3. 在實體類之間添加必要的關聯來明确彼此關系

4. 添加實作需求的必要屬性

領域模型與資料庫模型、資訊模型的差別

一個經常引起争論的問題是,領域模型與資料庫模型有什麼差別?

兩者有一些細微的差别,我們盡可能的使領域模型與資料庫模型一一對應。當然領域模型使用了面向對象的方法,如繼承、接口以及其它設計模式。在簡單情況下,領域模型隻保持了屬性,而沒有操作。相同的是兩者都是由多個類或者實體組成的關聯網絡。

可以為兩者的映射确定好規則,UML有一個缺點,太靈活,可以根據實際情況來選擇不同的實作方式,但是領域模型畢竟是給開發人員,最好确定映射規則,以便了解。多種不同實作方式導緻各自實作代碼不同。

領域模型不涉及具體的實作,我們可以使用EJB實作,也可以使用POJO實作,當我們使用了設計模式時,往往很難使用EJB來表現,這時隻有使用POJO。事實上,隻要我們确定了領域模型與資料庫模型的映射規則,就可以使用MDA工具輸入領域模型來生成EJB或者POJO代碼。

另外,通過詳細設計,資料庫模型還可以包括存儲過程、觸發器、索引等資料庫特有的對象。

領域模型也不同于資訊模型,資訊模型描述的範圍包括實體的屬性、類之間的關系(繼承、關聯、聚合)、分包,領域模型在此基礎上還描述了實體類和接口的行為。

詞彙表

詞彙表中包含了使用者使用的專業詞彙,在領域模型中起到提綱挈領的作用,同時規範了關鍵的業務詞彙用語。通過浏覽詞彙表,大概可以了解領域模型所要解決的問題領域。在開發過程中,如果需要新增屬性或者方法,開發人員可以依據詞彙表來給新的屬性、方法命名,能夠有效的避免了最終程式中用詞不一緻的情況,提高代碼的可讀性。

領域模型的内容

領域模型設計使用UML的類圖來表現。

領域模型可以包括實體和服務。

實體可以辨別作為對象的基本定義。辨別有兩種:有意義的辨別,例如:人的身份證号碼。無意義的辨別,例如:同一賬号的兩筆等額的存款交易都有一個計算機産生的交易号。

實體可以有行為,例如:新開賬戶、取款都是是賬戶實體的一個行為,這些行為是業務領域的實際操作。

另外,還有一種實體稱為值對象,這種實體基本上沒有業務方法,主要是起到類似資料字典般的查詢作用。

當領域中的一個重要行為或轉換操作不是實體對象本身的職責時,把操作作為一種獨立的接口加入模型,并聲明為服務。服務指為客戶做什麼,代表一種行為,而不是一個實體,是一個動詞而不是一個名詞。例如:将資金從一個賬戶轉移到另一個賬戶的功能是一個領域服務,包含了明顯的業務規則。轉賬的服務不能屬于任何一個賬戶對象,因為操作包含兩個賬号和一些全局規則。服務隻有行為,一般作為接口提供操作。

領域模型如何映射到設計和實作

傳統的辦法是分析階段時建立分析模型,到了設計階段根據分析模型的啟發建立設計模型。

這種方法需要建立兩個模型,而且分析模型和設計模型之間沒有直接映射關系,是在人腦中進行加工轉換的,這樣無法保證設計模型完整的繼承分析模型。如果模型無法映射到設計與實作,其價值何在?

由于架構固定,分析模型能夠根據架構映射到設計和實作,是以設計模型可以不必到達真實類的粒度。将兩者合一,使用一個分析模型(也稱作領域模型)就可以貫穿分析設計過程。

以WEB應用系統開發舉例,通過一個固定的J2EE架構可以将領域模型的實體的屬性對應到EntityBean,方法轉換為ApplicationService的方法,預設的基本方法(增删改查)不需要在領域模型中定義,這是為了讓分析人員将注意力集中在核心業務上。服務一般轉換為接口,被ApplicationService實作。從另外一個角度也可以認為通過MVC将領域模型的實體分解為Model-EntityBean和Controller-ApplicationService,服務直接轉換為Controller-ApplicationService。

小結如下:

實體預設的增删改行為(領域模型不需要定義)對應到Application Service的行為

實體的行為(領域模型定義)對應到Application Service的行為

服務對應到Application Service的行為,或者作為接口被Application Service實作

舉例:

賬戶實體有行為取款和存款。這兩個行為被映射到ApplicationService的2個方法:

deposit(Account acc,int qty);withdraw(Account acc,int qty);賬戶的屬性映射為Account的EntityBean。其餘的SessionBean,DAO,Action等都按照架構的原則生成。

另一方面,由于業務經常發生變化,保持一個穩定、易于修改的業務領域層顯得十分重要。通過固定的J2EE架構,一旦業務發生變化,可以快速定位到對應的業務實體和業務邏輯,提高軟體的可維護性。

使用模式

分析模式可以在領域模型的前期引入,取得初始化模型,不是從零開始,而是在一個已有的基礎上來模組化,可以提高效率。設計模式可以在領域模型的後期引入,去優化調整模型,删繁就簡,使提煉後的模型更加優美實用。

架構設計

架構是一個很寬泛的概念,為了更加清楚的說明問題,在軟體設計階段,我将架構簡單分為3種:應用系統的功能架構、技術架構和實體部署架構。功能和技術架構設計指導了整個團隊如何分工協作進行詳細設計。應用軟體的性能問題往往是由架構設計來決定的,是以需要在架構設計時考慮性能問題。

功能架構設計

應用系統的功能架構設計解決軟體在具體實作時使用的架構,代碼如何組織,各個子產品之間如何通訊,各個層次之間如何通訊,非功能需求如何嵌入功能需求中去,以及重用元件與各個子系統之間的接口關系。在業務流程圖中對業務進行了劃分,一般來說,可以在業務劃分的基礎上進行功能的劃分,此時需要根據軟體實作的一些原則進行分包結構的調整,例如:穩定依賴原則、穩定抽象原則、無循環的依賴原則等。

J2EE應用系統的MDPB開發方法

功能架構設計示意圖

技術架構設計

技術架構設計主要決定采用什麼技術路線、通訊機制等,例如采用J2EE的架構。采用一緻、穩定的技術架構,有助于提高技術人員的開發效率,整合已有的重用元件和其它系統的功能子產品,是以可以通過架構藍圖來事先規定每個項目采用的技術架構。

架構模式

依據Sun的Core J2EE Patterns列舉的模式建立适合的架構模式。

應用軟體的架構設計應該将業務邏輯代碼集中在ApplicationService中,封裝和內建後端代碼,保持業務層前端代碼要薄,隻是轉發,業務層後端代碼隻是基本方法(增删改)。

ApplicationService集中展現了領域模型中類的操作和服務。SessionBean負責事務的控制,DAO負責資料查詢。

使用者界面層有2個職責,分别是表現層和頁面跳轉邏輯層。

在這個過程中,可以采用AOP将非功能需求從功能需求中解耦出來。

J2EE應用系統的MDPB開發方法

架構模式示意圖 

部署架構設計

實體部署架構是指将軟體的各個功能子產品按照一定的架構分别部署在一個或者多個中間件軟體上,這些中間件軟體可能是分布在多台伺服器上的。例如,一個複雜的部署架構可以将軟體的不可間斷的核心業務子產品進行叢集部署,提高軟體的可靠性,另外的子產品分布部署在性能不等的伺服器上以滿足不同負載的需求,而所有這些子產品都是依賴于基礎子產品的,是以基礎子產品也可以單獨部署。另外部署在内部網或者網際網路也是需要考慮的重要因素,需要為此在軟體裡設計不同的安全措施。

在設計階段考慮部署架構,是對軟體的可靠性、安全性、性能,中間件平台和伺服器配置要求的綜合考慮,避免在系統測試階段或者正式上線後才發現軟體存在重大的設計缺陷。

架構設計階段的傳遞物是概要設計說明書,其内容應該包含應用系統的功能架構設計、技術架構設計和實體部署架構設計三個方面的内容。

資料庫設計

資料庫設計過程是領域模型的一個間接成果,按照一定轉換規則根據領域模型可以映射為資料庫實體模型。

使用OO-R映射或者人工設計資料庫實體模型都不是什麼難事,表的定義幾乎可以與領域模型中的實體一緻,當然,除了資料庫資料類型的轉換外,還需要考慮到實作過程中的性能、易用等原則,适當增加備援字段、索引等。

詳細設計

面向對象詳細設計應該怎麼做,詳細設計文檔應該怎麼寫?我想是很多人經常感到困惑的事情。傳統的詳細設計文檔分為輸入、算法、輸出,似乎和面向對象聯系不到一塊。

詳細設計比領域模型更接近代碼層,詳細設計是以上所有工作成果的延續,它承接界面原型設計,在界面層上繼續修訂,完成界面布局設計、界面跳轉邏輯設計,形成最終的界面設計;以領域模型為基礎,在架構設計指導下,使用具體程式設計語言,形成POJO、EJB、dotNET的實際代碼;資料庫實體在這個過程被進一步精化,并會根據實際情況設計出索引、視圖、存儲過程、觸發器等資料庫對象。

綜上所述,詳細設計可以分為3個方面開展:業務邏輯設計、資料庫設計精化、界面設計精化。以下隻對業務邏輯設計作介紹。

在本文例子中,由于主要的業務邏輯代碼集中在applicationService,是以詳細設計就是确定applicationService的業務邏輯方法如何用僞代碼實作,以及如何調用其他子產品的applicationService類方法。

舉例:

某一個applicationService類的一個方法的詳細設計如下:

XXposting()

if 領用了項目的物資 then

1. call XXAppSvc,生成一張從項目調撥到備品配件的調撥單,狀态設定為“完成”,

2. call YYAppSvc,生成一張從備品配件調撥回項目的數量為0的預調撥單,狀态設定為“未完成”,

3. call ZZAppSvc,生成一張申購單,狀态為“新增”,

4. updateStatus,更新搶修領料單的狀态為“已過帳”

Else if 選擇待配置設定物資 then

updateStatus,更新搶修領料單的狀态為“已過帳”(不必生成調撥單)

這種詳細設計類似于僞代碼,或者代碼注釋,篇幅很小,但保留了最有用的設計思想,可以使開發人員專注于寫出最有用的代碼和文檔。 

編碼實作

從領域模型驅動生成業務邏輯代碼和實體對象代碼,根據架構藍圖生成代碼層次結構,實作填空式程式設計。具體描述:領域模型中的實體屬性生成VO和Entity Bean,實體行為生成Application Service,實體的分包生成各個子產品,根據J2EE Web應用的架構藍圖生成整個應用的代碼架構,即各個層次的對象協作關系。代碼由業務邏輯層和表現層2部分組成,在業務邏輯層為delegate/fa?ade/appsvc/vo/entity/dao,在表現層為action/js/jsp,另外,根據資料庫設計的結果生成實際的資料庫表和對象,作為代碼編寫運作的調試基礎。

在業務邏輯的詳細設計中已經設計出Application Service的各個方法的僞代碼或者編碼思路,是以在編碼實作階段開發人員将根據詳細設計文檔在生成的Application Service方法中編寫代碼。

J2EE應用系統的MDPB開發方法

從領域模型和架構藍圖到業務邏輯代碼

同時,開發人員可以根據詳細設計階段更新後的界面原型來實作表現層代碼,即展現頁面-jsp和javascript,頁面跳轉邏輯-action。

J2EE應用系統的MDPB開發方法

從界面原型到表現層代碼

結語

通過幾個項目的實踐,驗證了這種開發方法具備很強的操作性,每一步都是為編碼作準備,沒有冗長多餘的文檔,既注重編碼實作,又兼顧分析與設計的過程。靈活方法過分注重編碼,不提前進行設計,這要求每一個人都具備較高的技術水準,直接将設計融入到編碼中,在現實中具備這種實施條件的團隊很少,而RUP屬于重量級過程,過分注重分析設計,項目組無法頂住長期作設計而不編碼的壓力。我認為,開發方法保持平衡與簡潔很重要。首先要取得分析設計與編碼的平衡,不能忽視分析設計的重要性,也不能先射擊再瞄準,直接就開始編碼。其次開發方法需要簡潔,分析與設計過程的每個步驟耗費工作量不大,文檔精煉,且能取得切實的效果,為編碼提供具體的幫助。

參考文獻

編寫有效用例, Alistair cockburn著

模型驅動設計-軟體核心複雜性應對之道, Eric evans著

統一軟體開發過程, Ivar Jacobson,Grady Booch,James Rumbaugh著

分析模式-可複用的對象模型, Martin Fowler著