紅知博客

          知其然,亦知其所以然
          posts - 32, comments - 35, trackbacks - 0, articles - 0
          用UML設(shè)計(jì)Java應(yīng)用程序

          本文的案例學(xué)習(xí)提供了一個(gè)例子,說(shuō)明如何將UML用在現(xiàn)實(shí)中。一個(gè)處理圖書(shū)館借閱和預(yù)定圖書(shū)和雜志的應(yīng)用程序,可以大到足夠檢驗(yàn)UML解決現(xiàn)實(shí)問(wèn)題能力的程度。但是如果太大的話,則不適合在雜志上發(fā)表。 在分析模型中,用用例和域分析描述了應(yīng)用程序。我們進(jìn)一步把它擴(kuò)展成設(shè)計(jì)模型。在設(shè)計(jì)模型中,我們描述了典型的技術(shù)解決方案細(xì)節(jié)。最后,我們編寫(xiě)了一段Java代碼(代碼連同完整的分析和設(shè)計(jì)模型放在網(wǎng)上,以一種包括評(píng)估版在內(nèi)的Rational Rose能夠識(shí)別的格式在線提供。)
          必須注意,這里只是一個(gè)可行的解決方案。可能會(huì)有許多其他的解決方案。沒(méi)有絕對(duì)正確的方案。當(dāng)然,有的方案更好一些,但只有不斷的實(shí)踐和努力的工作才能掌握相應(yīng)的技能。 1.需求(Requirements)
          典型地,由系統(tǒng)最終用戶的代表寫(xiě)出文本形式的需求規(guī)范文檔。對(duì)于該圖書(shū)館應(yīng)用程序來(lái)說(shuō),需求規(guī)范文檔應(yīng)該類似于這樣:
          1. 這是一個(gè)圖書(shū)館支持系統(tǒng);
          2. 圖書(shū)館將圖書(shū)和雜志借給借書(shū)者。借書(shū)者已經(jīng)預(yù)先注冊(cè),圖書(shū)和雜志也預(yù)先注冊(cè);
          3. 圖書(shū)館負(fù)責(zé)新書(shū)的購(gòu)買。每一本圖書(shū)都購(gòu)進(jìn)多本書(shū)。當(dāng)舊書(shū)超期或破舊不堪時(shí),從圖書(shū)館中去掉。
          4. 圖書(shū)管理員是圖書(shū)館的員工。他們的工作就是和讀者打交道并在軟件系統(tǒng)的支持下工作。
          5. 借閱人可以預(yù)定當(dāng)前沒(méi)有的圖書(shū)和雜志。這樣,當(dāng)他所預(yù)定的圖書(shū)和雜志歸還回來(lái)或購(gòu)進(jìn)時(shí),就通知預(yù)定人。當(dāng)預(yù)定了某書(shū)的借書(shū)者借閱了該書(shū)后,預(yù)定就取消。或者通過(guò)顯式的取消過(guò)程強(qiáng)行取消預(yù)定。
          6. 圖書(shū)館能夠容易地建立、修改和刪除標(biāo)題、借書(shū)者、借閱信息和預(yù)定信息。
          7. 系統(tǒng)能夠運(yùn)行在所有流行的技術(shù)環(huán)境中,包括Unix, Windows和OS/2,并應(yīng)有一個(gè)現(xiàn)代的圖形用戶界面 (GUI)。
          8. 系統(tǒng)容易擴(kuò)展新功能。
          系統(tǒng)的第一版不必考慮預(yù)定的圖書(shū)到達(dá)后通知預(yù)定人的功能,也不必檢查借書(shū)過(guò)期的情況。 2.分析(Analysis)
          系統(tǒng)分析的目的是捕獲和描述所有的系統(tǒng)需求,并且建立一個(gè)模型來(lái)定義系統(tǒng)中主要的域類。通過(guò)系統(tǒng)分析達(dá)到開(kāi)發(fā)者和需求者的理解和溝通。因此,分析一般都是分析員和用戶協(xié)作的產(chǎn)物。
          在這個(gè)階段,程序開(kāi)發(fā)者不應(yīng)該考慮代碼或程序的問(wèn)題;它只是理解需求和實(shí)現(xiàn)系統(tǒng)的第一步。
          2.1需求分析(Requirements Analysis)
          分析的第一步是確定系統(tǒng)能夠做什么?誰(shuí)來(lái)使用這個(gè)系統(tǒng)?這些分別叫角色(actors)和用例(use cases)。用例描述了系統(tǒng)提供什么樣的功能。通過(guò)閱讀和分析文檔,以及和潛在的用戶討論系統(tǒng)來(lái)分析用例。
          圖書(shū)館的角色定為圖書(shū)管理員和借書(shū)人。圖書(shū)管理員是軟件系統(tǒng)的用戶;而借書(shū)者則是來(lái)借閱或預(yù)定圖書(shū)雜志的客戶。偶爾,圖書(shū)管理員或圖書(shū)館的其他工作人員也可能是一個(gè)借書(shū)者。借書(shū)者不直接和系統(tǒng)交互,借書(shū)人的功能由圖書(shū)管理員代為執(zhí)行。
          圖書(shū)館系統(tǒng)中的用例有:
          1. 借書(shū)
          2. 還書(shū)
          3. 預(yù)定
          4. 取消預(yù)定
          5. 增加標(biāo)題
          6. 修改或刪除標(biāo)題
          7. 增加書(shū)目
          8. 刪除書(shū)目
          9. 增加借書(shū)者
          10. 修改或刪除借書(shū)者
          由于一本書(shū)通常有多個(gè)備份,因此系統(tǒng)必須將書(shū)的標(biāo)題和書(shū)目的概念區(qū)分開(kāi)。
          圖書(shū)館系統(tǒng)分析的結(jié)果寫(xiě)在UML 用例圖中,如圖1所示。每一個(gè)用例都附帶有文本文檔,描述用例和客戶交互的細(xì)節(jié)。文本是通過(guò)與客戶討論得到的。用例“借書(shū)”描述如下:
          1.如果借閱者沒(méi)有預(yù)定:
          h 確定標(biāo)題
          h 確定該標(biāo)題下有效的書(shū)目
          h 確定借書(shū)者
          h 圖書(shū)館將書(shū)借出
          h 登記一個(gè)新的借閱
          2.如果借閱者有預(yù)定:
          h 確定借書(shū)人
          h 確定標(biāo)題
          h 確定該標(biāo)題下有效的書(shū)目
          h 圖書(shū)館將相應(yīng)的書(shū)目借出
          h 登記一個(gè)新的借閱
          h 取消預(yù)定
          除了定義系統(tǒng)的功能需求之外,在分析過(guò)程中用例用于檢查是否有相應(yīng)的域類已經(jīng)被定義,然后他們可以被用在設(shè)計(jì)階段,確保解決方案可以有效地處理系統(tǒng)功能。可以在順序圖中可視化實(shí)現(xiàn)細(xì)節(jié)。

          圖1:角色和用例。分析中的第一步就是指出系統(tǒng)能被用來(lái)做什么,誰(shuí)將去使用它。它們分別就是用例和角色。所有的用例必須始于角色,而且有些用例也結(jié)束于角色。角色是位于你所工作的系統(tǒng)外部的人或其他系統(tǒng)。一臺(tái)打印機(jī)或一個(gè)數(shù)據(jù)庫(kù)都可能是一個(gè)角色。本系統(tǒng)有兩個(gè)角色:借閱者和圖書(shū)管理員。通過(guò)與用戶或客戶的討論,可以將每一個(gè)用例用文字進(jìn)行說(shuō)明。
          2.2域分析(Domain Analysis)
          系統(tǒng)分析也詳細(xì)地列出了域(系統(tǒng)中的關(guān)鍵類)。為了導(dǎo)出一個(gè)域分析,可以閱讀規(guī)范文檔(specifications)和用例,查找哪一些概念應(yīng)該被系統(tǒng)處理。或者組織一個(gè)集體討論,在用戶及領(lǐng)域?qū)<夜餐膮⑴c下指出系統(tǒng)中必須處理的關(guān)鍵概念,以及它們之間的關(guān)系。
          圖書(shū)館系統(tǒng)中的域類如下:borrowerinformation(如此命名是為了與用例圖中的角色borrower區(qū)分開(kāi)來(lái)),title,book title, magazine title, item, reservation和loan。這些類以及它們之間的關(guān)系記錄在類圖文檔中,如圖2所示。域類定義為Business object版型,Business object版型是一個(gè)用戶自定義的版型,指定該類的對(duì)象是關(guān)鍵域的一部分,并且應(yīng)該在系統(tǒng)中持久存儲(chǔ)。
          其中有些類有UML狀態(tài)圖,用來(lái)顯示這些類的對(duì)象可能具有的不同狀態(tài),以及觸發(fā)他們的狀態(tài)發(fā)生改變的事件。該例子中有狀態(tài)圖的類是item 和title類。
          用例lend item(借閱者沒(méi)有預(yù)定的情況)的順序圖顯示在圖3中。所有用例的順序圖都可從在線模型中查到。

          圖2:域類結(jié)構(gòu)。
          域分析詳細(xì)說(shuō)明了系統(tǒng)中的關(guān)鍵類。對(duì)每一個(gè)對(duì)象而言,如果它調(diào)用了其他對(duì)象的方法,那么在他們之間就用一條直線連結(jié)起來(lái),以顯示他們之間的關(guān)系。每一個(gè)代表類的四邊形被分成了三部分,最頂層包括類的名稱,中間一層是類的屬性,最底層是類的方法。類之間的直線是關(guān)聯(lián),用來(lái)指出一個(gè)對(duì)象調(diào)用另一個(gè)對(duì)象的方法。如果再仔細(xì)看,將會(huì)發(fā)現(xiàn)在Loan和Item之間的關(guān)聯(lián)關(guān)系中靠近Loan的一端有“0..1”,這代表關(guān)聯(lián)的重?cái)?shù)。重?cái)?shù)“0..1表示Item可以感知0個(gè)到1個(gè)loan。其他可能出現(xiàn)的重?cái)?shù)還有:“0..*”表示0或多;“1”表示就是1;“0”表示就是0,“1..*”表示1或多。
          當(dāng)對(duì)順序圖建模時(shí),必須提供窗體和對(duì)話框作為人機(jī)交互的界面。在本分析當(dāng)中,只要知道借書(shū)、預(yù)定和還書(shū)需要窗體就可以了。在此,詳細(xì)的界面不必考慮。
          為了把系統(tǒng)中的窗體類和域類分開(kāi),所有的窗體類組織在一起放在GUI Package包中。域類組織在一起放在Business Package包中。


          圖3:Lend item場(chǎng)景的順序圖。

          場(chǎng)景是從頭到尾實(shí)現(xiàn)一個(gè)用例的一次特定的過(guò)程。場(chǎng)景總是始于角色,而角色是屬于系統(tǒng)外部的。場(chǎng)景描繪了從所有角色的觀點(diǎn)出發(fā),完成一次系統(tǒng)動(dòng)作的完整過(guò)程。UML在用順序圖來(lái)圖示場(chǎng)景。本用例圖顯示了在借閱者沒(méi)有預(yù)定圖書(shū)的情況下的Lend用例。橫在圖的頂部的是參與交互的對(duì)象。自上而下表示時(shí)間的流逝。首先,圖書(shū)管理員嘗試去查找標(biāo)題。標(biāo)有“Lending Window”的是用戶界面,在分析階段作為一個(gè)粗略的對(duì)象。橫在順序圖中的每一個(gè)箭頭都是一次方法的調(diào)用,箭頭的首端是調(diào)用的對(duì)象,箭頭的末端是被調(diào)用的對(duì)象。
          3.設(shè)計(jì)(Design)
          設(shè)計(jì)階段對(duì)分析模型進(jìn)行擴(kuò)展并將模型進(jìn)一步細(xì)化,并考慮技術(shù)細(xì)節(jié)和限制條件。設(shè)計(jì)的目的是指定一個(gè)可行的解決方案,以便能很容易地轉(zhuǎn)變成為編程代碼。
          設(shè)計(jì)可以分成兩個(gè)階段:
          體系結(jié)構(gòu)設(shè)計(jì)階段(Architecture Design)。這是一個(gè)從較高層次的進(jìn)行的設(shè)計(jì),用來(lái)定義包(子系統(tǒng)),描述包之間的依賴性及通信機(jī)制。很自然,目的是要設(shè)計(jì)一個(gè)清晰簡(jiǎn)單的體系結(jié)構(gòu),有很少的依賴性,而且盡可能避免雙向依賴。詳細(xì)設(shè)計(jì)階段(Detailed Design)。在此階段,所有的類都詳盡地進(jìn)行描述,給編寫(xiě)代碼的程序員一個(gè)清晰的規(guī)范說(shuō)明。UML中的動(dòng)態(tài)模型用來(lái)說(shuō)明類的對(duì)象如何在特定的情況下做出相應(yīng)的表現(xiàn)。
          3.1體系結(jié)構(gòu)設(shè)計(jì)
          一個(gè)良好的體系結(jié)構(gòu)設(shè)計(jì)是一個(gè)可擴(kuò)展的和可改變的系統(tǒng)的基礎(chǔ)。包可能關(guān)注特定的功能領(lǐng)域或關(guān)注特定的技術(shù)領(lǐng)域。把應(yīng)用程序邏輯(域類)和技術(shù)邏輯分開(kāi)是至關(guān)重要的,這樣不管哪一部分的改變都不會(huì)影響其他的部分。
          本案例的包或叫子系統(tǒng)如下:
          User-Interface Package包。該包中的類基于Java AWT包,java AWT是一個(gè)用來(lái)書(shū)寫(xiě)用戶界面應(yīng)用程序的Java的標(biāo)準(zhǔn)庫(kù)。該包和Business-objects Package包協(xié)作。Business-objects Package包包含那些實(shí)際存儲(chǔ)數(shù)據(jù)的類。UI包調(diào)用Business 對(duì)象的操作,對(duì)他們進(jìn)行取出或插入數(shù)據(jù)操作。
          Business-object Package。該包包括域類,這些域類(如borrowerinformation,title,item,loan等)來(lái)自于分析模型。設(shè)計(jì)階段完整地定義了這些類的操作,并增加了一些其他細(xì)節(jié)來(lái)支持持續(xù)存儲(chǔ)。Business-object包與Database Package進(jìn)行協(xié)作。所有的Business-object類必須繼承Database Package中的persistent類。

          如果認(rèn)為有必要的話,在將來(lái)的版本中這些簡(jiǎn)化都可以很容易地被取消。
          分析階段的狀態(tài)圖也在設(shè)計(jì)階段細(xì)化了。狀態(tài)圖顯示了如何表示狀態(tài)及如何在系統(tǒng)中處理狀態(tài)。設(shè)計(jì)階段的title 類的狀態(tài)圖如圖6所示。其他的對(duì)象可以通過(guò)調(diào)用如圖所示的操作addreservation()和removereservation()來(lái)改變title對(duì)象的狀態(tài)。
          User-Interface Package。User-Interface Package位于其他包的“上面”。在系統(tǒng)中它為用戶提供輸出信息和服務(wù)。正如上面曾經(jīng)提到的,該包是基于標(biāo)準(zhǔn)Java AWT(abstract windows toolkit)類的。
          設(shè)計(jì)模型中的動(dòng)態(tài)模型放置在GUI包中,因?yàn)樗泻陀脩舻慕换ザ紡挠脩艚缑骈_(kāi)始。在此聲明,順序圖用來(lái)顯示動(dòng)態(tài)模型。用例在設(shè)計(jì)模型中的實(shí)現(xiàn)通過(guò)順序圖被詳細(xì)地顯示出來(lái),包括類中的實(shí)際操作。
          順序圖由一系列的交互構(gòu)成。在實(shí)現(xiàn)階段(編碼),考慮到具體情況,可能會(huì)有更多的交互。圖7顯示了add title用例的順序圖。實(shí)際的操作和特征值從在線模型代碼中可以看到。

          圖5:商業(yè)對(duì)象設(shè)計(jì)(Business-Object design)。
          本圖描述了在Business-Object包中的不同類的設(shè)計(jì)。設(shè)計(jì)包括定型模型,更完全地定制界面,給屬性選擇數(shù)據(jù)類型等等。
          6:Title的狀態(tài)圖。Title具有預(yù)定和非預(yù)定狀態(tài),在設(shè)計(jì)中,通過(guò)稱為“reservations”的矢量來(lái)實(shí)現(xiàn)。

          7:Add Title的順序圖。本圖中所涉及到的用戶界面問(wèn)題的詳細(xì)情況已經(jīng)超出了本文的討論范圍。

          協(xié)作圖可以作為順序圖的替代,如圖8所示:
          圖8:Add Title的協(xié)作圖。本圖中涉及到的用戶界面問(wèn)題的詳細(xì)情況已經(jīng)超出了本文討論的范圍
          3.3 用戶界面 設(shè)計(jì)(User-lnterface Design)
          設(shè)計(jì)階段的一個(gè)特定的活動(dòng)是創(chuàng)建用戶界面。
          圖書(shū)館系統(tǒng)的用戶界面基于用例,分為以下幾部分,每一部分都在主窗體菜單上給出一個(gè)單獨(dú)的菜單項(xiàng)。
          Functions:實(shí)現(xiàn)系統(tǒng)基本功能的窗體,通過(guò)它可以實(shí)現(xiàn)借閱、歸還和對(duì)圖書(shū)的預(yù)定。
          Information:查看系統(tǒng)信息的窗體,收集了借閱者和圖書(shū)的信息。
          Maintenance:維護(hù)系統(tǒng)的窗體,添加、修改和刪除標(biāo)題、借閱者和書(shū)目。
          圖9顯示了一個(gè)User-Interface Package中類圖的例子。其中包含了典型的AWT事件句柄。按鈕(button)、標(biāo)簽(label)和編輯(edit)等的屬性沒(méi)有顯示。
          典型地,每一個(gè)窗體都給出了系統(tǒng)的一個(gè)服務(wù),并且映射一個(gè)最初的用例(盡管并非所有的用戶界面都必須從用例中映射)。創(chuàng)建成功的用戶界面已經(jīng)超出了本文所討論的范圍。在此邀請(qǐng)讀者來(lái)考慮用symantec visual cafe 環(huán)境開(kāi)發(fā)的本應(yīng)用程序的UI代碼(已經(jīng)放在網(wǎng)上)。

          圖9:功能類圖模型。功能菜單中的用戶界面類一般都有1對(duì)1的關(guān)聯(lián)關(guān)系,表示需要建立關(guān)聯(lián)的窗口類,或者需要訪問(wèn)關(guān)聯(lián)的商業(yè)對(duì)象類。
          4.實(shí)現(xiàn)(Implementation)
          在構(gòu)造或稱實(shí)現(xiàn)階段進(jìn)行程序編寫(xiě)。該應(yīng)用程序要求能運(yùn)行在幾個(gè)不同的處理器和不同的操作系統(tǒng)上,因此選擇Java來(lái)實(shí)現(xiàn)系統(tǒng)。Java可以輕松地將邏輯類映射為代碼組件,因?yàn)樵陬惡蚃ava代碼文件之間有1對(duì)1的映射。
          圖10:組件圖顯示了依賴性。源代碼組件實(shí)現(xiàn)了域類,他們之間的關(guān)聯(lián)顯示為雙向依賴性

          圖10顯示,設(shè)計(jì)模型的組件視圖簡(jiǎn)單地將邏輯視圖中的類映射為組件視圖中的組件。每個(gè)邏輯視圖包含了一個(gè)指向邏輯視圖中類的連接,因此可以很容易地在不同的視圖之間導(dǎo)航(即便象本例只是簡(jiǎn)單地使用了文件名)。由于依賴性可以從邏輯視圖的類圖中得到,因此組件圖中沒(méi)有顯示組件之間的依賴性。
          編寫(xiě)代碼時(shí),從下面的設(shè)計(jì)模型的圖中取出規(guī)范說(shuō)明:
          1.類規(guī)范:每一個(gè)類的規(guī)范詳細(xì)地顯示了必要的屬性和操作。
          2.類圖:類圖由類構(gòu)成,顯示了類的結(jié)構(gòu)以及類之間的關(guān)系。
          3.狀態(tài)圖:類的狀態(tài)圖顯示了類可能具有的狀態(tài)以及需要處理的狀態(tài)轉(zhuǎn)移(以及觸發(fā)轉(zhuǎn)移的操作)。
          4.動(dòng)態(tài)圖(順序圖、協(xié)作圖和活動(dòng)圖):涉及到類的對(duì)象,顯示了類中的特定方法如何實(shí)現(xiàn),或?qū)ο笾g如何使用其它類的對(duì)象進(jìn)行交互。
          Database Package。Database Package向Business-object包中的類提供服務(wù),以便他們能夠持續(xù)地存儲(chǔ)。在當(dāng)前版本中,persistent類將把它的子類的對(duì)象存儲(chǔ)到文件系統(tǒng)的文件中。
          Utility Package。Utility Package包含了一些服務(wù),用來(lái)被系統(tǒng)中其他包調(diào)用。當(dāng)前,ObjId類是該包中的唯一的類。用來(lái)被整個(gè)系統(tǒng)包括User-Interface,Business-Object和Database package使用。
          這些包的內(nèi)部設(shè)計(jì)如圖4所示.

          圖4:圖書(shū)館應(yīng)用程序體系結(jié)構(gòu)設(shè)計(jì)總覽。

          本類圖顯示了應(yīng)用程序包以及它們之間的依賴性。Database包提供了persistence類。Utility包提供了Object ID類。Business-Object包包含了域類(詳細(xì)情況參見(jiàn)圖5)最后,UI包(在本例中它是基于標(biāo)準(zhǔn)Jaa AWT庫(kù))調(diào)用business對(duì)象中的操作來(lái)實(shí)現(xiàn)對(duì)他們的數(shù)據(jù)存取操作。,
          3.2詳細(xì)設(shè)計(jì)
          細(xì)節(jié)設(shè)計(jì)描述了新的技術(shù)性的類,如User-Interface和Database 包中的類,并且豐富了分析階段所形成的Business-Object類。類圖、狀態(tài)圖和動(dòng)態(tài)圖用的還是分析階段所形成的圖,但對(duì)他們定義的更加詳細(xì),具有了更高的技術(shù)水平。在分析階段對(duì)用例進(jìn)行的文字性描述在此用來(lái)證明用例在設(shè)計(jì)階段也能被處理。順序圖就是用來(lái)說(shuō)明用例如何在系統(tǒng)中被實(shí)現(xiàn)的。
          Database Package。應(yīng)用程序必須有持續(xù)存儲(chǔ)的對(duì)象。因此,必須增加數(shù)據(jù)層來(lái)提供這樣的服務(wù)。為簡(jiǎn)單起見(jiàn),我們將對(duì)象以文件的形式保存在磁盤上。存儲(chǔ)的細(xì)節(jié)被應(yīng)用程序隱藏起來(lái),只需調(diào)用諸如store(), update(),delete()和find()這樣的公共操作即可。這些都是persistent類的一部分,所有需要持續(xù)對(duì)象的類必須繼承它。
          對(duì)類進(jìn)行持續(xù)處理的一個(gè)重要因子就是ObjId類。它的對(duì)象用來(lái)引用系統(tǒng)中的任何持續(xù)對(duì)象(不管這個(gè)對(duì)象是在磁盤上還是已經(jīng)被讀進(jìn)了應(yīng)用程序之中)。ObjId是Object Identity的簡(jiǎn)寫(xiě),它是一個(gè)廣為應(yīng)用的技術(shù),用來(lái)有效地處理應(yīng)用程序中的對(duì)象引用。通過(guò)使用object identifiers,一個(gè)對(duì)象ID能被傳遞到普通的persistent.getobject()操作中,進(jìn)而該對(duì)象將被從持續(xù)的存儲(chǔ)體中取出或存儲(chǔ)。通常情況下,這些都是通過(guò)每個(gè)持續(xù)類的一個(gè)getobject操作完成的。當(dāng)然,持續(xù)類同時(shí)也作一些檢查或格式轉(zhuǎn)換的操作。一個(gè)對(duì)象標(biāo)識(shí)符也能作為一個(gè)參數(shù)很容易地在兩個(gè)操作之間傳遞(例如,一個(gè)查找特定對(duì)象的查詢窗口可以將它的查詢結(jié)果通過(guò)object id傳遞給另一個(gè)窗口 )。
          ObjId是一個(gè)系統(tǒng)中所有的包(User Interface , Business Object和Database)都能使用的通用類,所以在設(shè)計(jì)階段它被放置在Utility包中,而不是放在Database包中。
          當(dāng)前對(duì)persistent類的實(shí)現(xiàn)還能改進(jìn)。為此,定義persistent類的接口,方便持續(xù)存儲(chǔ)的改變。一些備選的方案可能是:將對(duì)象存儲(chǔ)在一個(gè)關(guān)系數(shù)據(jù)庫(kù)中或存儲(chǔ)在面向?qū)ο蟮臄?shù)據(jù)庫(kù)中,或使用Java 1.1所支持的持續(xù)對(duì)象來(lái)存儲(chǔ)他們。
          Business-Object Package。設(shè)計(jì)階段的Business-Object包基于相應(yīng)的分析階段的放置域類的包。類和類之間的關(guān)系以及他們的行為繼續(xù)保留,只是被描述的更為詳細(xì),包括他們的關(guān)系和行為如何被實(shí)現(xiàn)。
          分析模型中的一些操作中被翻譯成設(shè)計(jì)模型的操作,另一些改了名字。這是很正常的事,因?yàn)榉治鲭A段得到的是每一個(gè)類的草圖,而設(shè)計(jì)階段是對(duì)系統(tǒng)的詳細(xì)描述。因此,設(shè)計(jì)模型的操作必須有設(shè)計(jì)良好的特征值和返回值(由于空間限制,圖5沒(méi)有顯示,但他們?cè)谠诰€模型中都有)。注意以下所列的設(shè)計(jì)和分析階段的變化:
          1. 系統(tǒng)的當(dāng)前版本不要求檢查書(shū)目是否按時(shí)歸還,也不要求處理預(yù)定的次序。因此沒(méi)有在loan 和reservation類中設(shè)置日期屬性。
          2. 除了最長(zhǎng)借閱期外,對(duì)雜志和書(shū)標(biāo)題的處理方式是一樣的。因此分析階段的子類magazine title和book title被認(rèn)為在設(shè)計(jì)階段是不必要的,而是在title類中增加type屬性來(lái)指出該標(biāo)題引用的是一本書(shū)還是一本雜志。在面向?qū)ο蟮脑O(shè)計(jì)中不存在設(shè)計(jì)不能簡(jiǎn)化分析的說(shuō)法。

          5.用例圖和規(guī)范:當(dāng)開(kāi)發(fā)者需要了解更多的關(guān)于系統(tǒng)如何被使用的信息時(shí)(當(dāng)開(kāi)發(fā)者感到他或她已經(jīng)迷失在一片細(xì)節(jié)中),他們顯示了系統(tǒng)被使用的結(jié)果。
          很自然,設(shè)計(jì)中的某些缺陷可以在編碼階段發(fā)現(xiàn)。可能需要一些新的操作或修改某些操作,這意味著開(kāi)發(fā)者必須改變?cè)O(shè)計(jì)模型。這在所有的工程中都會(huì)發(fā)生。重要的是將設(shè)計(jì)模型和代碼同步,以便使模型能夠成為系統(tǒng)的最終文檔。
          這里給出了loan 類和部分titleframe類的Java代碼。整個(gè)應(yīng)用程序的Java代碼可以從網(wǎng)上查到。當(dāng)學(xué)習(xí)這些代碼時(shí),注意結(jié)合UML模型,考慮UML結(jié)構(gòu)是如何被轉(zhuǎn)變?yōu)榇a的。注意以下幾點(diǎn):
          1.Java包規(guī)范是與類所屬的邏輯視圖或組件視圖中相應(yīng)的包等值的代碼。
          2.私有屬性對(duì)應(yīng)于模型中指定的屬性;并且,很自然Java 方法對(duì)應(yīng)于模型中的操作。
          3.ObjId類(對(duì)象標(biāo)識(shí)符)被調(diào)用來(lái)實(shí)現(xiàn)關(guān)聯(lián)。也就是說(shuō),關(guān)聯(lián)通常和類一起保存(因?yàn)镺bjId類是持續(xù)的)。
          程序清單1的代碼示例來(lái)自于loan類,loan類是一個(gè)Business-Object類,用來(lái)存放借閱信息。由于該類主要是信息的存放處,因此程序的實(shí)現(xiàn)是直接的,代碼也簡(jiǎn)單。大多數(shù)的功能繼承了Database 包中的Persistent類。該類的唯一屬性是對(duì)象標(biāo)識(shí)符,將item和borrowerinformation類關(guān)聯(lián)起來(lái)。并且這些關(guān)聯(lián)屬性也在Write()和Read()操作中被保存。
          試著在Add Title順序圖(圖7)上下文中檢驗(yàn)一下程序清單2中顯示的Addbutton_Clicked()操作。結(jié)合順序圖閱讀代碼,可以看出:它就是另一個(gè)對(duì)順序圖所表達(dá)的協(xié)作關(guān)系的更為詳細(xì)的描述。
          所有設(shè)計(jì)模型中的順序圖的編碼都包含在源代碼當(dāng)中(操作名和類名顯示在順序圖中)
          5.測(cè)試和部署(Test and Deployment)
          編碼結(jié)束后,UML的使用還沒(méi)有停止。例如,可以檢驗(yàn)用例能否在已完成的應(yīng)用程序中得到很好的支持。對(duì)于系統(tǒng)的部署來(lái)說(shuō),利用模型和本文可以做一份得心應(yīng)手的文檔。
          6.總結(jié)
          本學(xué)習(xí)案例的不同部分由一組人分別來(lái)設(shè)計(jì)完成。他們以做實(shí)際工程的方式努力完成該工作。盡管不同的階段和活動(dòng)似乎是獨(dú)立的,而且以嚴(yán)格的順序來(lái)管理,但在實(shí)際工作中仍然有很多反復(fù)。設(shè)計(jì)中的經(jīng)驗(yàn)和教訓(xùn)反饋到分析模型,實(shí)現(xiàn)階段所發(fā)現(xiàn)的新情況在設(shè)計(jì)模型中更改或更新。這就是建立面向?qū)ο笙到y(tǒng)的一般方法。
          本文摘錄自UML Toolkit,New York:Wiley & Sons,1998. Hans-Erik Erikkson是一個(gè)有名的C++和OO技術(shù)方面的作者。Magnus Penker是Astrakan培訓(xùn)副主席,Astrankan是一個(gè)瑞典專攻OO建模和設(shè)計(jì)的公司。

          原文鏈接:http://www.umlchina.com/Indepth/DesignJava.htm
          模型及源碼:http://www.umlchina.com/zippdf/libraryjava.zip
          附:主要術(shù)語(yǔ)中英文對(duì)照
          actor:角色
          use case:用例
          domain:域
          domain analysis:域分析
          specification:規(guī)范文檔
          sequence diagram:順序圖
          collaboration diagram:協(xié)作圖
          component diagram:組件圖
          state diagram:狀態(tài)圖
          dependency:依賴性
          attribute:屬性
          method:方法
          operation:操作
          association:關(guān)聯(lián)
          multiplicity:重?cái)?shù)
          class:類
          object:對(duì)象
          package:包
          implementation:實(shí)現(xiàn)
          deployment:部署

          附:源代碼
          Listing 1. Loan class. Loan is a Business-object class used for storing information about a loan. Most of the functionality is inherited from the Persistent class in the Database Package.

          // Loan.java: represents a loan. The loan refer to one
          // title and one borrower.
          //

          Package bo;
          import util.ObjId;
          import db.*;
          import java.io.*;
          import java.util.*;

          public class Loan extends Persistent
          {
          private ObjId item;
          private ObjId borrower;
          public Loan()
          {
          }
          public Loan(ObjId it, ObjId b)
          {
          item = it;
          borrower = b;
          }
          public BorrowerInformation getBorrower()
          {
          BorrowerInformation ret = (BorrowerInformation) Persistent.getObject(borrower);
          return ret;
          }
          public String getTitleName()
          {
          Item it = (Item) Persistent.getObject(item);
          return it.getTitleName();
          }
          public Item getItem()
          {
          Item it =
          (Item) Persistent.getObject(item);
          return it;
          }
          public int getItemId()
          {
          Item it = (Item) Persistent.getObject(item);
          return it.getId();
          }
          public void write(RandomAccessFile out)
          throws IOException
          {
          item.write(out);
          borrower.write(out);

          }
          public void read(RandomAccessFile in)
          throws IOException
          {
          item = new ObjId();
          item.read(in);
          borrower = new ObjId();
          borrower.read(in);
          }
          }

          Listing 2. TitleFrame Class. This is another, more detailed description of the collaboration described by the diagram in Figure 7.

          // TitleFrame.java
          //

          Package ui;

          import bo.*;
          import util.*;

          import java.awt.*;

          public class TitleFrame extends Frame {
          private Title current;

          void addButton_Clicked(Event event) {
          if (Title.findOnName(titleField.getText()) != null)
          {
          new MessageBox(
          this,"A Title with that name already exists!");
          return;
          }
          if (Title.findOnISBN(isbnField.getText()) != null)
          {
          new MessageBox(
          this,"A title with the
          same isbn/nr field already exists!");
          return;
          }
          int type = 0;
          if (bookButton.getState() == true)
          type = Title.TYPE_BOOK;
          else if (magazineButton.getState() == true)
          type = Title.TYPE_MAGAZINE;
          else
          {
          new MessageBox(this,"Please give type of title!");
          return;
          }
          current =
          new Title(
          titleField.getText(),
          authorField.getText(),
          isbnField.getText(),
          type);
          int itemno;
          if (itemsField.getText().equals(""))
          itemno = 0;
          else
          itemno = Integer.valueOf(
          itemsField.getText()).intValue();
          if (itemno > 25)
          {
          new MessageBox(this, "Maximum number of items is 25!");
          return;
          }
          for (int i = 0; i <\<> itemno; i++)
          {
          Item it = new Item(current.getObjId(),i+1);
          it.store();
          current.addItem(it.getObjId());
          }
          current.store();
          titleField.setText("");
          authorField.setText("");
          isbnField.setText("");
          itemsField.setText("");
          bookButton.setState(false);
          magazineButton.setState(false);

          }

          void cancelButton_Clicked(Event event) {
          dispose();
          }

          public TitleFrame() {

          //{{INIT_CONTROLS
          setLayout(null);
          addNotify();
          resize(
          insets().left + insets().right + 430,insets().top +
          insets().bottom + 229);
          titleLabel = new java.awt.Label("Title Name");
          titleLabel.reshape(
          insets().left + 12,insets().top + 24,84,24);
          add(titleLabel);
          titleField = new java.awt.TextField();
          titleField.reshape(
          insets().left + 132,insets().top + 24,183,24);
          add(titleField);
          authorField = new java.awt.TextField();
          authorField.reshape(
          insets().left + 132,insets().top + 60,183,24);
          add(authorField);
          isbnField = new java.awt.TextField();
          isbnField.reshape(
          insets().left + 132,insets().top + 96,183,24);
          add(isbnField);
          label1 = new java.awt.Label("ISBN / Nr");
          label1.reshape(
          insets().left + 12,insets().top + 96,84,24);
          add(label1);
          label2 = new java.awt.Label("Author");
          label2.reshape(
          insets().left + 12,insets().top + 60,84,24);
          add(label2);
          addButton = new java.awt.Button("Insert");
          addButton.reshape(
          insets().left + 348,insets().top + 24,60,24);
          add(addButton);
          cancelButton = new java.awt.Button("Close");
          cancelButton.reshape(
          insets().left + 348,insets().top + 192,60,24);
          add(cancelButton);
          label3 = new java.awt.Label("Items available");
          label3.reshape(
          insets().left + 12,insets().top + 192,108,24);
          add(label3);
          itemsField = new java.awt.TextField();
          itemsField.reshape(
          insets().left + 132,insets().top + 192,36,23);
          add(itemsField);
          Group1 = new CheckboxGroup();
          bookButton =
          new java.awt.Checkbox("Book", Group1, false);
          bookButton.reshape(
          insets().left + 132,insets().top + 132,108,24);
          add(bookButton);
          magazineButton =
          new java.awt.Checkbox("Magazine", Group1, false);
          magazineButton.reshape(
          insets().left + 132,insets().top + 156,108,24);
          add(magazineButton);
          label4 = new java.awt.Label("Type");
          label4.reshape(
          insets().left + 12,insets().top + 132,108,24);
          add(label4);
          setTitle("Insert Title Window");
          //}}
          bookButton.setState(true);
          titleField.requestFocus();

          //{{INIT_MENUS
          //}}
          }

          public TitleFrame(String title) {
          this();
          setTitle(title);
          }

          public synchronized void show() {
          move(50, 50);
          super.show();
          }

          public boolean handleEvent(Event event) {
          if (event.id == Event.WINDOW_DESTROY) {
          dispose();
          return true;
          }
          if (event.target == addButton && event.id ==
          Event.ACTION_EVENT) {
          addButton_Clicked(event);
          return true;
          }
          if (event.target == cancelButton && event.id ==
          Event.ACTION_EVENT) {
          cancelButton_Clicked(event);
          return true;
          }
          return super.handleEvent(event);
          }

          //{{DECLARE_CONTROLS
          java.awt.Label titleLabel;
          java.awt.TextField titleField;
          java.awt.TextField authorField;
          java.awt.TextField isbnField;
          java.awt.Label label1;
          java.awt.Label label2;
          java.awt.Button addButton;
          java.awt.Button cancelButton;
          java.awt.Label label3;
          java.awt.TextField itemsField;
          java.awt.Checkbox bookButton;
          CheckboxGroup Group1;
          java.awt.Checkbox magazineButton;
          java.awt.Label label4;
          //}}

          //{{DECLARE_MENUS
          //}}
          }
          我要啦免费统计
          主站蜘蛛池模板: 临猗县| 盈江县| 开化县| 临湘市| 临邑县| 井冈山市| 梁河县| 土默特右旗| 金湖县| 江城| 社会| 德兴市| 漳平市| 射洪县| 广州市| 江永县| 大冶市| 民权县| 黄浦区| 鄯善县| 志丹县| 通江县| 建阳市| 广西| 津市市| 高淳县| 新营市| 铜鼓县| 桑日县| 梨树县| 柯坪县| 北票市| 洪雅县| 元江| 辛集市| 衡山县| 西平县| 饶平县| 深圳市| 丹巴县| 清新县|