· 泛化
泛化關係是類元的一般描述和具體描述之間的關係,具體描述建立在一般描述的基礎之上,並對其進行了擴充。具體描述與一般描述完全一致所有特性、成員和關係,並且包含補充的資訊。例如,抵押是借貸中具體的一種,抵押保持了借貸的基本特性並且加入了附加的特性,如房子可以作為借貸的一種抵押品。一般描述被稱作父,具體描述被稱作子如借貸是父而抵押則是子。泛化在類元(類、介面、資料類型、用例、參與者、訊號等等)、包、狀態機器和其他元素中使用。在類中,術語超類和子類代表父和子。
泛化用從子指向父的箭頭表示,指向父的是一個空三角形(如 圖 4 – 7 表示)。多個泛化關係可以用箭頭線組成的樹來表示,每一個分支指向一個子類。
圖 4–7 泛化標記法
泛化的用途
泛化有兩個用途。第一個用途是用來定義下列情況:當一個變數(如參數或過程變數)被聲明承載某個給定類的值時,可使用類(或其他元素)的執行個體作為值,這被稱作可替代性原則(由 Barbara Liskov 提出)。該原則表明無論何時祖先被聲明了,則後代的一個執行個體可以被使用。例如,如果一個變數被聲明擁有借貸,那麼一個抵押對象就是一個合法的值。
泛化使得多態操作成為可能,即操作的實現是由它們所使用的對象的類,而不是由調用者確定的。這是因為一個父類可以有許多子類,每個子類都可實現定義在類整體集中的同一操作的不同變體。例如,在抵押和汽車借貸上計算利息會有所不同,它們中的每一個都是父類借貸中計算利息的變形。一個變數被聲明擁有父類,接著任何子類的一個對象可以被使用,並且它們中的任何一個都有著自己獨特的操作。這一點特別有用,因為在不需要改變現有多態調用的情況下就可以加入新的類。例如,一種新的借貸可被新增加進來,而現存的用來計算利息操作的代碼仍然可用。一個多態操作可在父類中聲明但無實現,其後代類需補充該操作的實現。這種不完整操作是抽象的(其名稱用斜體表示)。
泛化的另一個用途是在共用祖先所定義的成分的前提下允許它自身定義增加的描述,這被稱作繼承。繼承是一種機制,通過該機制類的對象的描述從類及其祖先的聲明部分聚集起來。繼承允許描述的共用部分只被聲明一次而可以被許多類所共用,而不是在每個類中重複聲明並使用它,這種共用機制減小了模型的規模。更重要的是,它減少了為了模型的更新而必須做的改變和意外的前後定義不一致。對於其他成分,如狀態、訊號和用例,繼承通過相似的方法起作用。
· 繼承
每一種泛化元素都有一群組繼承特性。對於任何模型元素的包括約束。對類元而言,它們同樣包括一些特性(如屬性、操作和訊號接收)和關聯中的參與者。一個子類繼承了它的所有祖先的可繼承的特性。它的完整特性包括繼承特性和直接聲明的特性。
對類元而言,沒有具有相同特徵標記的屬性會被多次聲明,無論直接的或繼承的,否則將發生衝突,且模型形式錯誤。換而言之,祖先聲明過的屬性不能被後代再次聲明。如果類的介面一致(具有同樣的參數、約束和含義),操作可在多個類中聲明。附加的聲明是多餘的。一個方法在階層中可以被多個類聲明,附在後代上的方法替代(重載)在任何祖先中聲明過的具有相同特徵標記的方法。如果一個方法的兩個或多個副本被一個類繼承(通過不同類的多重繼承),那麼它們會發生衝突並且模型形式錯誤(一些程式設計語言允許顯式選定其中的一種方法。我們發現如果在後代類中重新定義方法會更簡單、安全)。元素中的約束是元素本身及它所有祖先的約束的聯合體,如果它們存在不一致,那麼模型形式錯誤。
在一個具體的類中,每一個繼承或聲明的操作都必須有一個已定義的方法,無論是直接定義或從祖先那裡繼承而來的。
· 多重繼承
如果一個類元有多個父類,那麼它從每一父類那裡都可得到繼承資訊( 4-8 )。它的特徵(屬性、操作和訊號)是它的所有父類特徵的聯合。如果同一個類作為父類出現在多條路徑上,那麼它的每一個成員中只有它的一個拷貝。如果有著同樣特徵的特性被兩個類聲明,而這兩個類不是從同一祖先那裡繼承來的(即獨立聲明),那麼聲明會發生衝突並且模型形式錯誤。因為經驗告訴我們設計者應自行解決這個問題,所以 UML 不提供這種情形的衝突解決方案。像 Eiffel 這樣的語言允許衝突被程式設計者明確地解決,這比隱式的衝突解決原則要安全,而這些原則經常使開發人員大吃一驚。
圖 4–8 多重繼承
· 單分類和多重分類
在最簡單的形式中,一個對象僅屬於一個類,許多物件導向的語言有這種限制。一個對象僅屬於一個類並沒有邏輯上的必要性,我們只要從多個角度同時觀察一下真實世界的對象就可以發現這一點。在 UML 更概括的形式中,一個對象可以有一個或多個類。對象看起來就好像它屬於一個隱式類,而這個類是每個直接父類的子類 — 多重繼承可以免去再聲明一個新類,這可提高效率。
· 靜態與動態類元
在最簡單的形式中,一個對象在被建立後不能改變它的類。我們再次說明,這種限制並沒有邏輯上的必要性,而是最初目地是使物件導向程式設計語言的實現更容易些。在更普遍的形式下,一個對象可以動態改變它的類,這麼做會得到或失去一些屬性或關聯。如果對象失去了它們,那麼在它們中的資訊也就失去了並且過後也不能被恢複,哪怕這個對象變回了原來的類。如果這個對象得到了屬性或關聯,那麼它們必須在改變時就初始化,就像初始化一個新對象一樣。
當多重分類和動態分類一起使用時,一個對象就可以在它的生命期內得到或失去類。動態類有時被稱作角色或類型。一個常見的建模模式是每個對象有一個唯一的靜態固有類(即不能在對象的生命期內改變的類),加上零個或多個可以在對象生命期內加入或移走的角色類。固有類描述了這個對象的基本特性,而角色類描述了暫時的特性。雖然許多程式設計語言不支援類聲明中的多重動態分類,然而它仍然是一個很有用的建模概念,並且可以被映射到關聯上。