http://www./oobject/201211231.asp 在UML 2.0的13種圖形中,,類圖是使用頻率最高的UML圖之一,。Martin Fowler在其著作《UML Distilled: A Brief Guide to the Standard Object Modeling Language, Third Edition》(《UML精粹:標(biāo)準(zhǔn)對象建模語言簡明指南(第3版)》)中有這么一段:“If someone were to come up to you in a dark alley and say, 'Psst, wanna see a UML diagram?' that diagram would probably be a class diagram. The majority of UML diagrams I see are class diagrams.”(“如果有人在黑暗的小巷中向你走來并對你說:'嘿,,想不想看一張UML圖,?’那么這張圖很有可能就是一張類圖,我所見過的大部分的UML圖都是類圖”),,由此可見類圖的重要性,。 類圖用于描述系統(tǒng)中所包含的類以及它們之間的相互關(guān)系,幫助人們簡化對系統(tǒng)的理解,,它是系統(tǒng)分析和設(shè)計階段的重要產(chǎn)物,,也是系統(tǒng)編碼和測試的重要模型依據(jù)。 1. 類 類(Class)封裝了數(shù)據(jù)和行為,,是面向?qū)ο蟮闹匾M成部分,,它是具有相同屬性、操作,、關(guān)系的對象集合的總稱,。在系統(tǒng)中,每個類都具有一定的職責(zé),,職責(zé)指的是類要完成什么樣的功能,,要承擔(dān)什么樣的義務(wù)。一個類可以有多種職責(zé),,設(shè)計得好的類一般只有一種職責(zé),。在定義類的時候,將類的職責(zé)分解成為類的屬性和操作(即方法),。類的屬性即類的數(shù)據(jù)職責(zé),,類的操作即類的行為職責(zé),。設(shè)計類是面向?qū)ο笤O(shè)計中最重要的組成部分,也是最復(fù)雜和最耗時的部分,。 在軟件系統(tǒng)運行時,,類將被實例化成對象(Object),對象對應(yīng)于某個具體的事物,,是類的實例(Instance),。 類圖(Class Diagram)使用出現(xiàn)在系統(tǒng)中的不同類來描述系統(tǒng)的靜態(tài)結(jié)構(gòu),它用來描述不同的類以及它們之間的關(guān)系,。 在系統(tǒng)分析與設(shè)計階段,,類通常可以分為三種,,分別是實體類(Entity Class),、控制類(Control Class)和邊界類(Boundary Class),下面對這三種類加以簡要說明: (1) 實體類:實體類對應(yīng)系統(tǒng)需求中的每個實體,,它們通常需要保存在永久存儲體中,,一般使用數(shù)據(jù)庫表或文件來記錄,實體類既包括存儲和傳遞數(shù)據(jù)的類,,還包括操作數(shù)據(jù)的類,。實體類來源于需求說明中的名詞,如學(xué)生,、商品等,。 (2) 控制類:控制類用于體現(xiàn)應(yīng)用程序的執(zhí)行邏輯,提供相應(yīng)的業(yè)務(wù)操作,,將控制類抽象出來可以降低界面和數(shù)據(jù)庫之間的耦合度,。控制類一般是由動賓結(jié)構(gòu)的短語(動詞+名詞)轉(zhuǎn)化來的名詞,,如增加商品對應(yīng)有一個商品增加類,,注冊對應(yīng)有一個用戶注冊類等 (3) 邊界類:邊界類用于對外部用戶與系統(tǒng)之間的交互對象進行抽象,主要包括界面類,,如對話框,、窗口、菜單等,。 在面向?qū)ο蠓治龊驮O(shè)計的初級階段,,通常首先識別出實體類,繪制初始類圖,,此時的類圖也可稱為領(lǐng)域模型,,包括實體類及其它們之間的相互關(guān)系。 2. 類的UML圖示 在UML中,類使用包含類名,、屬性和操作且?guī)в蟹指艟€的長方形來表示,,如定義一個Employee類,它包含屬性name,、age和email,,以及操作modifyInfo(),在UML類圖中該類如圖1所示: 圖1 類的UML圖示 圖1對應(yīng)的Java代碼片段如下:
在UML類圖中,,類一般由三部分組成: (1) 第一部分是類名:每個類都必須有一個名字,,類名是一個字符串。 (2) 第二部分是類的屬性(Attributes):屬性是指類的性質(zhì),,即類的成員變量,。一個類可以有任意多個屬性,也可以沒有屬性 UML規(guī)定屬性的表示方式為: 可見性 名稱:類型 [ = 缺省值 ] 其中:
(3) 第三部分是類的操作(Operations):操作是類的任意一個實例對象都可以使用的行為,,是類的成員方法。 UML規(guī)定操作的表示方式為: 可見性 名稱(參數(shù)列表) [ : 返回類型] 其中:
在類圖2中,,操作method1的可見性為public(+),,帶入了一個Object類型的參數(shù)par,返回值為空(void),;操作method2的可見性為protected(#),,無參數(shù),返回值為String類型,;操作method3的可見性為private(-),,包含兩個參數(shù),其中一個參數(shù)為int類型,,另一個為int[]類型,,返回值為int類型。 圖2 類圖操作說明示意圖 由于在Java語言中允許出現(xiàn)內(nèi)部類,,因此可能會出現(xiàn)包含四個部分的類圖,,如圖3所示: 圖3 包含內(nèi)部類的類圖 類與類之間的關(guān)系(1) 在軟件系統(tǒng)中,類并不是孤立存在的,,類與類之間存在各種關(guān)系,,對于不同類型的關(guān)系,UML提供了不同的表示方式,。 1. 關(guān)聯(lián)關(guān)系 關(guān)聯(lián)(Association)關(guān)系是類與類之間最常用的一種關(guān)系,,它是一種結(jié)構(gòu)化關(guān)系,用于表示一類對象與另一類對象之間有聯(lián)系,,如汽車和輪胎,、師傅和徒弟、班級和學(xué)生等等,。在UML類圖中,,用實線連接有關(guān)聯(lián)關(guān)系的對象所對應(yīng)的類,在使用Java,、C#和C++等編程語言實現(xiàn)關(guān)聯(lián)關(guān)系時,,通常將一個類的對象作為另一個類的成員變量。在使用類圖表示關(guān)聯(lián)關(guān)系時可以在關(guān)聯(lián)線上標(biāo)注角色名,,一般使用一個表示兩者之間關(guān)系的動詞或者名詞表示角色名(有時該名詞為實例對象名),,關(guān)系的兩端代表兩種不同的角色,因此在一個關(guān)聯(lián)關(guān)系中可以包含兩個角色名,,角色名不是必須的,,可以根據(jù)需要增加,,其目的是使類之間的關(guān)系更加明確。 如在一個登錄界面類LoginForm中包含一個JButton類型的注冊按鈕loginButton,,它們之間可以表示為關(guān)聯(lián)關(guān)系,,代碼實現(xiàn)時可以在LoginForm中定義一個名為loginButton的屬性對象,其類型為JButton,。如圖1所示: 圖1 關(guān)聯(lián)關(guān)系實例 圖1對應(yīng)的Java代碼片段如下:
在UML中,,關(guān)聯(lián)關(guān)系通常又包含如下幾種形式: (1) 雙向關(guān)聯(lián) 默認情況下,關(guān)聯(lián)是雙向的,。例如:顧客(Customer)購買商品(Product)并擁有商品,,反之,賣出的商品總有某個顧客與之相關(guān)聯(lián),。因此,,Customer類和Product類之間具有雙向關(guān)聯(lián)關(guān)系,如圖2所示: 圖2 雙向關(guān)聯(lián)實例 圖2對應(yīng)的Java代碼片段如下:
(2) 單向關(guān)聯(lián) 類的關(guān)聯(lián)關(guān)系也可以是單向的,,單向關(guān)聯(lián)用帶箭頭的實線表示,。例如:顧客(Customer)擁有地址(Address),則Customer類與Address類具有單向關(guān)聯(lián)關(guān)系,,如圖3所示: 圖3 單向關(guān)聯(lián)實例 圖3對應(yīng)的Java代碼片段如下:
(3) 自關(guān)聯(lián) 在系統(tǒng)中可能會存在一些類的屬性對象類型為該類本身,,這種特殊的關(guān)聯(lián)關(guān)系稱為自關(guān)聯(lián)。例如:一個節(jié)點類(Node)的成員又是節(jié)點Node類型的對象,,如圖4所示: 圖4 自關(guān)聯(lián)實例 圖4對應(yīng)的Java代碼片段如下:
(4) 多重性關(guān)聯(lián) 多重性關(guān)聯(lián)關(guān)系又稱為重數(shù)性(Multiplicity)關(guān)聯(lián)關(guān)系,,表示兩個關(guān)聯(lián)對象在數(shù)量上的對應(yīng)關(guān)系。在UML中,,對象之間的多重性可以直接在關(guān)聯(lián)直線上用一個數(shù)字或一個數(shù)字范圍表示,。 對象之間可以存在多種多重性關(guān)聯(lián)關(guān)系,常見的多重性表示方式如表1所示: 表1 多重性表示方式列表
例如:一個界面(Form)可以擁有零個或多個按鈕(Button),,但是一個按鈕只能屬于一個界面,因此,,一個Form類的對象可以與零個或多個Button類的對象相關(guān)聯(lián),,但一個Button類的對象只能與一個Form類的對象關(guān)聯(lián),,如圖5所示: 圖5 多重性關(guān)聯(lián)實例 圖5對應(yīng)的Java代碼片段如下:
(5) 聚合關(guān)系 聚合(Aggregation)關(guān)系表示整體與部分的關(guān)系,。在聚合關(guān)系中,成員對象是整體對象的一部分,,但是成員對象可以脫離整體對象獨立存在,。在UML中,聚合關(guān)系用帶空心菱形的直線表示,。例如:汽車發(fā)動機(Engine)是汽車(Car)的組成部分,,但是汽車發(fā)動機可以獨立存在,因此,汽車和發(fā)動機是聚合關(guān)系,,如圖6所示: 圖6 聚合關(guān)系實例 在代碼實現(xiàn)聚合關(guān)系時,,成員對象通常作為構(gòu)造方法、Setter方法或業(yè)務(wù)方法的參數(shù)注入到整體對象中,,圖6對應(yīng)的Java代碼片段如下:
(6) 組合關(guān)系 組合(Composition)關(guān)系也表示類之間整體和部分的關(guān)系,,但是在組合關(guān)系中整體對象可以控制成員對象的生命周期,一旦整體對象不存在,,成員對象也將不存在,,成員對象與整體對象之間具有同生共死的關(guān)系。在UML中,,組合關(guān)系用帶實心菱形的直線表示,。例如:人的頭(Head)與嘴巴(Mouth),嘴巴是頭的組成部分之一,,而且如果頭沒了,,嘴巴也就沒了,因此頭和嘴巴是組合關(guān)系,,如圖7所示: 圖7 組合關(guān)系實例 在代碼實現(xiàn)組合關(guān)系時,,通常在整體類的構(gòu)造方法中直接實例化成員類,圖7對應(yīng)的Java代碼片段如下:
類與類之間的關(guān)系(2) 2. 依賴關(guān)系 依賴(Dependency)關(guān)系是一種使用關(guān)系,,特定事物的改變有可能會影響到使用該事物的其他事物,,在需要表示一個事物使用另一個事物時使用依賴關(guān)系。大多數(shù)情況下,,依賴關(guān)系體現(xiàn)在某個類的方法使用另一個類的對象作為參數(shù),。在UML中,依賴關(guān)系用帶箭頭的虛線表示,,由依賴的一方指向被依賴的一方,。例如:駕駛員開車,在Driver類的drive()方法中將Car類型的對象car作為一個參數(shù)傳遞,,以便在drive()方法中能夠調(diào)用car的move()方法,,且駕駛員的drive()方法依賴車的move()方法,因此類Driver依賴類Car,,如圖1所示: 圖1 依賴關(guān)系實例 在系統(tǒng)實施階段,,依賴關(guān)系通常通過三種方式來實現(xiàn),第一種也是最常用的一種方式是如圖1所示的將一個類的對象作為另一個類中方法的參數(shù),,第二種方式是在一個類的方法中將另一個類的對象作為其局部變量,,第三種方式是在一個類的方法中調(diào)用另一個類的靜態(tài)方法。圖1對應(yīng)的Java代碼片段如下:
3. 泛化關(guān)系 泛化(Generalization)關(guān)系也就是繼承關(guān)系,,用于描述父類與子類之間的關(guān)系,,父類又稱作基類或超類,,子類又稱作派生類。在UML中,,泛化關(guān)系用帶空心三角形的直線來表示,。在代碼實現(xiàn)時,我們使用面向?qū)ο蟮睦^承機制來實現(xiàn)泛化關(guān)系,,如在Java語言中使用extends關(guān)鍵字,、在C++/C#中使用冒號“:”來實現(xiàn)。例如:Student類和Teacher類都是Person類的子類,,Student類和Teacher類繼承了Person類的屬性和方法,,Person類的屬性包含姓名(name)和年齡(age),每一個Student和Teacher也都具有這兩個屬性,,另外Student類增加了屬性學(xué)號(studentNo),,Teacher類增加了屬性教師編號(teacherNo),Person類的方法包括行走move()和說話say(),,Student類和Teacher類繼承了這兩個方法,,而且Student類還新增方法study(),Teacher類還新增方法teach(),。如圖2所示: 圖2 泛化關(guān)系實例 圖2對應(yīng)的Java代碼片段如下:
4. 接口與實現(xiàn)關(guān)系 在很多面向?qū)ο笳Z言中都引入了接口的概念,,如Java、C#等,,在接口中,,通常沒有屬性,而且所有的操作都是抽象的,,只有操作的聲明,,沒有操作的實現(xiàn)。UML中用與類的表示法類似的方式表示接口,,如圖3所示: 圖3 接口的UML圖示 接口之間也可以有與類之間關(guān)系類似的繼承關(guān)系和依賴關(guān)系,,但是接口和類之間還存在一種實現(xiàn)(Realization)關(guān)系,在這種關(guān)系中,,類實現(xiàn)了接口,,類中的操作實現(xiàn)了接口中所聲明的操作。在UML中,,類與接口之間的實現(xiàn)關(guān)系用帶空心三角形的虛線來表示,。例如:定義了一個交通工具接口Vehicle,包含一個抽象操作move(),,在類Ship和類Car中都實現(xiàn)了該move()操作,,不過具體的實現(xiàn)細節(jié)將會不一樣,如圖4所示: 圖4 實現(xiàn)關(guān)系實例 實現(xiàn)關(guān)系在編程實現(xiàn)時,,不同的面向?qū)ο笳Z言也提供了不同的語法,,如在Java語言中使用implements關(guān)鍵字,而在C++/C#中使用冒號“:”來實現(xiàn),。圖4對應(yīng)的Java代碼片段如下:
實例分析1——登錄模塊 某基于C/S的即時聊天系統(tǒng)登錄模塊功能描述如下: 用戶通過登錄界面(LoginForm)輸入賬號和密碼,,系統(tǒng)將輸入的賬號和密碼與存儲在數(shù)據(jù)庫(User)表中的用戶信息進行比較,驗證用戶輸入是否正確,,如果輸入正確則進入主界面(MainForm),,否則提示“輸入錯誤”。 根據(jù)以上描述繪制初始類圖,。 參考解決方案: 參考類圖如下: 考慮到系統(tǒng)擴展性,,在本實例中引入了抽象數(shù)據(jù)訪問接口IUserDAO,再將具體數(shù)據(jù)訪問對象注入到業(yè)務(wù)邏輯對象中,,可通過配置文件(如XML文件)等方式來實現(xiàn),,將具體的數(shù)據(jù)訪問類類名存儲在配置文件中,如果需要更換新的具體數(shù)據(jù)訪問對象,,只需修改配置文件即可,,原有程序代碼無須做任何修改。 類說明:
方法說明:
實例分析2——注冊模塊 某基于Java語言的C/S軟件需要提供注冊功能,,該功能簡要描述如下: 用戶通過注冊界面(RegisterForm)輸入個人信息,用戶點擊“注冊”按鈕后將輸入的信息通過一個封裝用戶輸入數(shù)據(jù)的對象(UserDTO)傳遞給操作數(shù)據(jù)庫的數(shù)據(jù)訪問類,,為了提高系統(tǒng)的擴展性,,針對不同的數(shù)據(jù)庫可能需要提供不同的數(shù)據(jù)訪問類,因此提供了數(shù)據(jù)訪問類接口,,如IUserDAO,,每一個具體數(shù)據(jù)訪問類都是某一個數(shù)據(jù)訪問類接口的實現(xiàn)類,如OracleUserDAO就是一個專門用于訪問Oracle數(shù)據(jù)庫的數(shù)據(jù)訪問類,。 根據(jù)以上描述繪制類圖,。為了簡化類圖,,個人信息僅包括賬號(userAccount)和密碼(userPassword),且界面類無需涉及界面細節(jié)元素,。 參考解決方案: 在以上功能說明中,,可以分析出該系統(tǒng)包括三個類和一個接口,這三個類分別是注冊界面類RegisterForm,、用戶數(shù)據(jù)傳輸類UserDTO,、Oracle用戶數(shù)據(jù)訪問類OracleUserDAO,接口是抽象用戶數(shù)據(jù)訪問接口IUserDAO,。它們之間的關(guān)系如下: (1) 在RegisterForm中需要使用UserDTO類傳輸數(shù)據(jù)且需要使用數(shù)據(jù)訪問類來操作數(shù)據(jù)庫,,因此RegisterForm與UserDTO和IUserDAO之間存在關(guān)聯(lián)關(guān)系,在RegisterForm中可以直接實例化UserDTO,,因此它們之間可以使用組合關(guān)聯(lián),。 (2) 由于數(shù)據(jù)庫類型需要靈活更換,因此在RegisterForm中不能直接實例化IUserDAO的子類,,可以針對接口IUserDAO編程,,再通過注入的方式傳入一個IUserDAO接口的子類對象(在本書后續(xù)章節(jié)中將學(xué)習(xí)如何具體實現(xiàn)),因此RegisterForm和IUserDAO之間具有聚合關(guān)聯(lián)關(guān)系,。 (3) OracleUserDAO是實現(xiàn)了IUserDAO接口的子類,,因此它們之間具有類與接口的實現(xiàn)關(guān)系。 (4) 在聲明IUserDAO接口的增加用戶信息方法addUser()時,,需要將在界面類中實例化的UserDTO對象作為參數(shù)傳遞進來,,然后取出封裝在UserDTO對象中的數(shù)據(jù)插入數(shù)據(jù)庫,因此addUser()方法的函數(shù)原型可以定義為:public boolean addUser(UserDTO user),,在IUserDAO的方法addUser()中將UserDTO類型的對象作為參數(shù),,故IUserDAO與UserDTO存在依賴關(guān)系。 通過以上分析,,該實例參考類圖如圖1所示: 圖1 注冊功能參考類圖 注意:在繪制類圖或其他UML圖形時,,可以通過注釋(Comment)來對圖中的符號或元素進行一些附加說明,如果需要詳細說明類圖中的某一方法的功能或者實現(xiàn)過程,,可以使用如圖2所示表示方式: 圖2 類圖注釋實例 實例分析3——售票機控制程序 某運輸公司決定為新的售票機開發(fā)車票銷售的控制軟件,。圖I給出了售票機的面板示意圖以及相關(guān)的控制部件。 圖I 售票機面板示意圖 售票機相關(guān)部件的作用如下所述: (1) 目的地鍵盤用來輸入行程目的地的代碼(例如,,200表示總站),。 (2) 乘客可以通過車票鍵盤選擇車票種類(單程票、多次往返票和座席種類),。 (3) 繼續(xù)/取消鍵盤上的取消按鈕用于取消購票過程,,繼續(xù)按鈕允許乘客連續(xù)購買多張票。 (4) 顯示屏顯示所有的系統(tǒng)輸出和用戶提示信息。 (5) 插卡口接受MCard(現(xiàn)金卡),,硬幣口和紙幣槽接受現(xiàn)金,。 (6) 打印機用于輸出車票。 (7) 所有部件均可實現(xiàn)自檢并恢復(fù)到初始狀態(tài),。 現(xiàn)采用面向?qū)ο蠓椒ㄩ_發(fā)該系統(tǒng),,使用UML進行建模,,繪制該系統(tǒng)的初始類圖,。 參考解決方案: 參考類圖如下: 類說明:
方法說明:
|
|