第五章 靜態建模:類圖和對象圖
用面向對象的方法處理實際問題時,需要建立面向對象的模型。構成面向對象模型的基本元素有類(class)、對象(objects)、類與類之間的關係等
4.1 類和對象
所謂對象就是可以控制和操作的實體,它可以是一個設備,一個組織或一個商務。類是對象的抽象描述,它包括屬性的描述和行爲的描述兩個方面;屬性描述類的基本特徵,行爲描述類具有的功能,也就是對該類的對象可以進行哪些操作;對象是類的實例化,所有的操作都是針對對象進行的
構建面向對象模型的基礎是類、對象和它們之間的關係
4.2 類圖
類圖是用類和它們之間的關係描述系統的一種圖示,是從靜態角度表示系統的,因此類圖屬於一種靜態模型。類圖是構建其他圖的基礎,沒有類圖,就沒有狀態圖、協作圖等
類圖中允許出現的模型元素只有類和它之間的關係
4.2.1 定義類
所定義的類通常要有這樣兩個特點:一是使用來自問題域的概念,二是類的名字用該類實際代表的涵義命名
l 有沒有一定要存儲或分析的信息?如果存在,那麼該信息可能就是一個類
l 有沒有外部系統?如果有,外部系統可以看作類,該類可以是本系統所包含的類,也可以是本系統與之交互的類
l 有沒有模塊、類庫、組件等?
l 系統中是否有被控制的設備?
l 有無需要表示的組織機構?
l 系統中有哪些角色?
4.2.2 名字、屬性和操作
屬性有不同的可見性(visibility),利用可見性可以控制外部事物對類中屬性的操作方式,有三種:公有的(public)、私有的(private)和保護的(protected)
在類圖中,(+)表示公有的,(-)表示私有的,如果沒有表示未定義
類的屬性中還可以有一種能被該類的所有對象共享的屬性,稱之爲類的作用域屬性(class-scope attribute),也稱作爲類變量(class variable)
描述屬性的語法: 可見性 屬性名 : 類型名 = 初值 {性質串}
Java語言實現圖4-6如下:
public class invoice { public double amount; public Date data=new Date(); public String customer; public String specification; public String administrator=”unspecified”; static private int number_of_invoices=0;
public invoice() //構造函數 { //部分初始化工作可在此進行 number_of_invoices ++; } //類的其他操作方法寫在這裏 } |
存取或改變屬性值或執行某個動作都是操作,操作說明了該類能做什麼工作。類將數據和對數據進行處理的函數封裝起來,形成了一個完整的整體。
描述操作的語法爲: 可見性 操作名(參數表) : 返回值類型 {性質串}
操作可以看作是類的一個接口,通過該接口實現內、外信息的交互。
4.2.3 基本類型的使用
4.3 關係
類與類之間通常有關聯、通用化(繼承)、依賴和精化等四種關係
4.3.1 關聯關係
關聯用於描述類與類之間的連接,也是對象與對象之間的關聯;如果某兩個類的對象之間存在可以互相通信的關係,或者說對象雙方能夠感知另一方,那麼這兩個類之間就存在關聯關係。
根據不同的含義,關聯可以分爲普通、遞歸、限定、或、有序、三元關聯和聚合
4.3.1.1 普通關聯
最常見的一種關聯,只要類與類之間存在連接關係就可以用普通關聯表示。
表示“某作家使用計算機”,黑三角的尖角指明這個關聯只能用在尖角所指的類上;如果類與類之間的關聯是單向的,稱爲導航關聯;
表示“人可以擁有0至多個小汽車”,只有箭頭所指的方向上纔有這種關聯關係,上圖表明瞭人擁有小汽車,但是小汽車被人擁有的情況沒有表示出來,其實普通關聯是導航關聯的一種特例;
在類圖中圖示關聯中的數量關係—重數,表示數量關係:
0..1 表示零到一個對象 0..*或* 表示多個對象 5..17 表示5到17個對象
如果圖中沒有明確表示,那麼就是1
上圖表示:人可以擁有多輛小汽車,小汽車可以被1至多個人擁有
再如下圖:
表示:保險公司有0或多個保險合同,這些合同與1個或多個客戶有關;客戶有0或多個保險合同,這些合同都與1個保險公司有關;保險合同位於一家保險公司和一個或多個客戶之間,用它建立保險公司和客戶之間的保險關係;保險合同用0或1個保險單表示,也就是合同的書面表示;一個保險單表示一份保險合同
多對多的雙向關聯,可以轉化成兩個一對多的關聯來實現
4.3.1.2 對象圖
類圖表示類和類之間的關係,對象圖則表示在某一時刻這些類的具體實例和這些實例之間的具體連接關係,其實表達對象圖和類圖幾乎沒有什麼區別,只是名字下面有下劃線
4.3.1.3 遞歸關聯
如果一個類與它本身有關聯關係,那麼此關聯稱爲遞歸關聯(recursive association),遞歸關聯指的是同類的對象之間語義上的連接。
4.3.1.4 關聯中的角色
任何關聯關係中都涉及到與此關聯有關的角色,也就是與此關聯相連的類中的對象所扮演的角色。引入角色的好處是:指明瞭類和類的對象之間的聯繫(CONTEXT),注意,角色名不是類的組成部分,一個類可以在不同的關聯中扮演不同的角色
人在“駕駛”這個關聯關係中,人扮演“駕駛員”司機的角色,車的所有權可由汽車公司扮演
人在“結婚”這個遞歸關係中,一個人扮演丈夫,另一個人就扮演妻子,如果沒有結婚,那麼這些角色也就不能應用了
4.3.1.5 限定關聯
限定關聯用於一對多或多對多的關聯關係中。在限定關聯中,使用限定詞將關聯中多的那一端的具體對象分成對象集。限定詞可以理解爲一種關鍵詞,用關鍵詞把所有的對象分開。利用限定關聯可以把模型中的重數從一對多變成一對一
從油畫類到圖畫類的關聯,圖畫用它的ID號表示
4.3.1.6 或關聯
所謂或關聯就是對二個或更多個關聯附加的約束條件,使類中的對象一次只能應用於一種關聯關係
人與保險合同的關聯關係不能同一般公司與保險公司的關聯關係同時發生
4.3.1.7 有序關聯
對象與對象之間的連接可以具有一定的次序,就像應該把窗口安排在屏幕之上一樣
4.3.1.8 關聯類
與一個關聯關係相連的類,稱作關聯類。關聯類並不位於表示關聯關係的直線兩端,而是對應一個實際的關聯,用關聯類表示該實際關聯的一些附加信息
隊列就是電梯控制器類與電梯類的關聯關係上的關聯類。電梯控制器通過讀取隊列信息,選擇一個合適的電梯爲乘客服務,關聯類也有屬性、操作和關聯
4.3.1.9 三元關聯
類與類之間的關聯關係,不僅限於兩個類之間,多個類之間也可以有關聯關係。如果有三個類之間有關聯關係,則稱之爲三元關聯
扮演保險客戶角色的“人”可以有0至多個保險合同,每個保險合同都與一家保險公司有關,保險公司扮演着承保者的角色,人和保險合同通過0或1個保險單建立三元關聯
4.3.1.10 聚合(aggregation)
聚合是關聯的特例。如果類與類之間的關係具有“整體與部分”的特點,則把這樣的關係稱爲聚合。
識別聚合關係的常用方法是尋找“由……構成”、“包含”、“是……的一部分”,這些字句很好地反映了相關類之間的“整體—一部分”關係
聚合還有二種特殊的聚合方式,共享聚合、複合聚合
如果聚合關係中的出於部分方的對象同時參與了多個處於整體方對象的構成,則該聚合稱爲共享聚合,一般做爲整體方的重數不是1,那麼就是共享聚合,它是一個網狀結構的關聯關係
如果構成整體類的部分類,完全隸屬於整體類,則這樣的聚合就是複合聚合,也就是說,如果沒有整體類則部分類也沒有存在的價值,部分類的存在是因爲有整體類的存在;整體方的重數必須是0或1,它是一個樹狀結構的關聯關係
複合聚合的實現方式一般是將部分類中的對象作爲整體類的成員對象(member object),將部分類封裝(encapsulating)在整體類中
4.3.2 通用化
一個類(通用元素)的所有信息(屬性和操作)能被另一個類(具體元素)繼承,繼承某個類的類中不僅可以有屬於自己的信息,而且還擁有了被繼承類中的信息,這種機制就是通用化。
UML中的通用化是通用元素和具體元素之間的一種分類關係。引入通用化的好處在於由於把一般的公共信息放在通用元素中,處理某個具體特殊情況時只需定義該情況的個別信息,這樣就只需要定義新擴充或更改的信息,舊的信息可以不必修改(仍可繼續使用)。
通用化用於類、用例等各種模型元素,注意:通用化針對類型,而不針對實例,比如:一個類繼承另一個類,但一個對象不能繼承另一個對象
通用化分成普通通用化和受限通用化
4.3.2.1 普通通用化
沒有具體對象的類稱作抽象類,抽象類一般做爲父類,用於描述其它類(子類)的公共屬性和行爲(操作)。比如交通工具類,很難想象它的具體實例,但是它描述了交通工具的一般特徵,加上{abstract}標記
抽象類一般都帶有抽象的操作,抽象操作僅僅用來描述該抽象類的所有子類應有什麼樣的行爲,抽象操作只標記出返回值、操作的名稱和參數表,關於操作的的具體實現細節並不詳細寫出來,而是由繼承抽象類的子類實現;這樣,子類可以重新定義父類的操作,但重新定義的操作的標記(返回值、名稱和參數表)應和父類一樣
4.3.2.2 受限通用化
給通用化關係附加一個約束條件,進一步說明該通用化的使用方法或擴充方法,這樣的通用化關係稱爲受限通用化。預定義的約束有四種:多重、不相交、完全和不完全
多重繼承指的是,子類的子類可以同時繼承多個上一級子類
與多重繼承相對立的是不相交繼承,即一個子類不能同時繼承多個上一級子類,一般不做特別聲明,一般的繼承都是不相交繼承
完全繼承指的是父類的所有子類都被窮舉完畢,不可能再有其它的未列出的子類存在
不完全繼承與完全繼承相反,父類的子類並不是無一遺漏地列出,而是隨着問題不斷地解決,不斷地補充和完善,也正是這一點爲日後系統的擴充和維護帶來極大的方便。默認一般是不完全繼承
4.3.3 依賴和精化的關係
依賴關係描述的兩個模型元素(類、組合、用例等)之間的語義上的連接關係。其中一個模型元素是獨立的,另一個模型元素是非獨立的(依賴的),它依賴於獨立的模型元素,如果獨立的模型元素髮生改變,將會影響依賴該模型元素的模型元素。
比如,某個類中使用的另一個類的對象做爲操作的參數,則這兩個類之間就具有依賴關係,類似的依賴關係還有一個類存取另一個類中的全局對象,以及一個類調用另一個類中的類作用域操作。
精化關係用於表示同一事物的兩種描述之間的關係。對同一事物的兩種描述建立在不同的抽象層上。精化關係常用於模型化表示同一事物的不同實現
精化用於模型的協調。
4.4 約束和派生規則
UML中的規則稱爲約束和派生。約束用於限制一個模型,派生用於描述某種事物產生的規則。關聯關係可以被約束,也可以派生
如果一個關聯是另一個關聯的子集,則它們之間就會存在約束關聯
派生是由現有的關聯關係衍生而來,派生的關聯名稱前加一條斜線
出租公司和很多客戶有租車合同,這裏面有些人很重要,於是在公司和客戶之間直接派生出“/VIP客戶”的關聯關係
屬性也可以被約束和派生,比如約束屬性:
+status: Status = unpaid {unpaid, paid} +color: Color = red {red, green, yellow} -administrator: String = “wwcd” |
派生屬性一般是由其它屬性通過某種方式計算得來
通用化關係只有約束,沒有派生,四種約束(多重、不相交、完全和不完全)
對角色的約束爲了防止一個對象所扮演的多個角色連在一起,當然對時間也有約束
UML使用五種語法機制表示這些約束和派生規則(見書第四章30頁)
4.5 接口
接口通常被描述爲抽象操作,也就是隻用標識(返回值、操作名稱、參數表)說明它的行爲,而真正實現部分放在使用該接口的元素中,這樣,應用該接口的不同元素就可以對接口採用不同的實現方法。接口的具體實現過程、方法,對調用該接口的對象是透明的
4.6 包
包(package)是一種組合機制,把各種各樣的模型元素通過內在的語義連在一起成爲一個整體就叫做包。包通常用於對模型的組織管理,因此有時將包稱爲子系統(subsystem)。包擁有自己的模型元素,包與包之間不能共用一個相同的模型元素。
包能夠引用來自其它包的模型元素,當有引用發生,那麼包與包之間就建立了關係,它們之間允許建立的關係有依賴、精化和通用化
包與聚合很相似,如果一個包有模型元素構成的(擁有自己的內容),那麼該包是複合聚合;如果一個包從其它的包中引用模型元素,該包是共享聚合
包的可見性除了公有、私有、保護外,還有一種是實現。實現可見性與私有可見性很相似,但是有依賴關係的包可用。如果一個包有實現可見性,則不允許其它包引用該包(即無依賴關係)
包也可以有接口,接口與包之間用實線相連,接口通常由包中的一個或多個類實現
4.7 模塊
模塊(templet)是一個尚未完全具體說明的類。模塊中提供參數表,利用參數表向模塊傳遞信息可最終形成用戶需要的具體類。由於給定不同的參數便可確定不同的類,所以模塊能夠說明許多類,故又稱模塊是一個用參數表示的類
4.8 模型質量
模型要抓住各個重要方面,其次,模型要易於通信,具有明確的目標,易於維護,保證一致性和完整性等