我們引入了UML類圖的概念
比較了在Java編程語言和UML類圖中表示類
屬性
操作和關聯關系的不同之處
下面我們來看看如何在UML中表示兩個重要的Java概念——繼承
接口
繼承
在Java中
我們可以聲明一個類擴展(extends)另一個類
還可以聲明一個類實現(implements)一個或者多個接口
下面我們來看看如何在UML中表達這些概念
下面是三個Java類的基本骨架
第一個類是代表某種支付方式的Payment抽象類
另外兩個類分別擴展Payment類
描述兩種不同的支付方式
/** 描述支付方式的抽象類 */
abstract public class Payment {
public Payment() { }
public Payment(BigDecimal amount) {
this
amount = amount;
}
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this
amount = amount;
}
private BigDecimal amount;
}
/** 一個擴展了Payment類的子類
描述信用卡支付方式 */
public class CreditCardPayment extends Payment {
public CreditCardPayment() {
}
public CreditCardPayment(BigDecimal amount) {
super(amount);
}
public String getCardNumber() {
return cardNumber;
}
public void setCardNumber(String cardNumber) {
this
cardNumber = cardNumber;
}
public boolean authorize() {
return false; //暫不實現
}
private String cardNumber;
}
/** 一個擴展了Payment類的子類
描述現金支付方式 */
public class CashPayment extends Payment {
public CashPayment() {
super();
}
public CashPayment(BigDecimal amount) {
super(amount);
}
public BigDecimal getAmountTendered() {
return amountTendered;
}
public void setAmountTendered(BigDecimal amountTendered) {
this
amountTendered = amountTendered;
}
private BigDecimal amountTendered;
public BigDecimal calcChange() {
return amountTendered
subtract(super
getAmount());
}
}
圖一用UML顯示了同樣的三個類
在操作和屬性聲明中
類型和參數之類的細節都沒有顯示出來
這是為了更清楚地顯示出類的整體結構以及各個類之間的關系
圖一
UML一般化關系
Java中的extends關鍵詞聲明了繼承關系
相當於UML中的
一般化
(Generalization
也譯為
泛化
)關系
在UML圖形中用子類向超類的實線空心封閉箭頭表示
圖一額外增加了一個Sale類
這是為了更清楚地說明UML一般化關系與UML定向關聯關系所用箭頭的不同
關聯關系與一般化關系的另一個不同之處在於
一般化關系的兩端不需要說明多重性或角色名稱
顯然
UML類圖比三個Java源代碼文件更清楚直觀地顯示出了三個類之間的繼承關系
如果你要與別人探討設計思路
繪制UML草圖也要比直接使用代碼簡單快捷得多
也許有人會說
系統的類結構圖就在他們的頭腦中
他們只需要直接使用Java代碼
實際上
對於規模較大的系統
這種說法顯然是不成立的
即使對於規模較小的系統
如果一定的時間之後要由其他程序員修改
沒有UML圖也會寸步難行——很難保證每一個人都了解你頭腦中的類結構圖
在UML中
抽象類的標志是類的名字以斜體顯示
在白板或紙張上手工畫UML草圖時
很難區分字體是否是斜體
為此
一些人建議這些場合可以在類名稱的右下角加上{abstract}標記以示區別
另一些人認為
在白板上寫{abstrac t}顯得太羅嗦
他們傾向於打破UML常規
在類名稱的右下角加上一個
表示零個實例
如果在該位置寫上
則表示該類是一個singleton類(永遠只有一個實例的類)
如果在該位置寫上N
則表示它是一個枚舉類(擁有固定實例數量的類
如一星期中的天數
彩虹的顏色
等等)
不過
這一切都不是標准的UML
只能用於手工繪制UML圖的場合
看來也不可能得到UML建模工具的支持
歷史知識
UML首先由Rational公司的一個工作組發明
Ration公司是UML建模工具Rose的生產者
UML於
年的OOPSLA會議上被公諸於世
隨後
OMG(對象管理組織)於
年采用了UML規范
不難理解
繼續負責發展UML規范的OMG任務組包含了來自幾乎所有主流UML工具廠商的代表
因此
除了嚴格遵從規范的UML軟件工具
在一些書籍或網頁上發現不規范的UML符號也不足為怪
繼承使得一個類能夠使用另一個類的屬性和方法
就象使用自己的屬性和方法一樣
當這類繼承機制第一次出現時
人們普遍把它視為重用現有代碼的理想方法
令人遺憾的是
規模過於龐大的繼承樹變得很脆弱
修改繼承樹的一部分
就會在整棵繼承樹中引起一系列的連帶反映
在面向對象的編程中
如果要實現有效的封裝
就應該讓改動局部化
即一個地方的改動不至於引起其他地方的變化
而修改繼承樹一個地方引起其他地方的變化恰恰違背了上述設計思想
UML圖使得我們能夠方便地掌握繼承關系圖
從而為應用繼承關系帶來了方便
那麼
什麼時候適合運用繼承關系呢?按照《Java Design》一書
對於超類A和子類B
執行如下檢查
命題
B是一個由A扮演的角色
不成立
B永遠不需要變形成為其他某些類別中的對象
B擴展而不是覆蓋或廢棄A的行為
A不僅僅是一個工具類(一些可以重用的實用功能)
對於一個問題域(特定的業務對象環境)
A和B定義了同一類型的對象
或者是用戶事務
角色
實體(團體
位置或其他東西)
或其他物體的相似類別
如果上述任意一個判斷不成立
那麼把A和B定義成繼承關系可能是不合適的
改用關聯關系可能更加穩固
正確
例如
圖二違背上面的第一個判斷
因為
雇員是一個由人扮演的角色
成立
另外
它還違背了第二個判斷
因為雇員確實可能改變其類別(身份)
例如某個時候它可能是顧客
這樣
一個既是顧客又是雇員的人就要有兩個獨立的對象來描述
從而使保存在Person類裡面的信息重復出現
帶來了兩個數據副本之間數據不一致的風險
圖二
不恰當的extends用法
圖三顯示了改用關聯關系後的UML圖
現在
一個人可以在同一時刻(或不同時刻)既是顧客又是雇員(或任意一種)
圖三
改用關聯關系
接口
Java編程語言中接口(Interface)的概念也能夠與UML概念匹配
UML中的接口是一種實現繼承的形式
但這種繼承形式與Java中通過關鍵詞extends實現的繼承有所不同
在Java中
extends關鍵詞描述了一種繼承形式
它既繼承接口也繼承行為
這種類型的繼承有時被稱為Sub
classing
與其他的面象對象編程語言不同
Java類只能從一個類繼承
許多時候
設計UML圖的人熟悉多種編程語言
常常會引入多重繼承的思想
例如C++的多重繼承思想
從已有的Java代碼生成UML圖(這個過程稱為反向工程)不會帶來多重繼承的問題
但如果要求一個Java程序員去實現一個帶有多重繼承的UML類圖
就會出現問題
如果多重繼承中的超類是純抽象類
這部分類可以用Java的接口來描述
但是
如果只做這種轉換不足以把UML類圖中的多重繼承全部轉換成單重繼承
這時就必須修改UML類圖重新建模了
雖然Java不支持C++之類語言那樣的多重繼承
但它支持實現多重接口
這種由Java關鍵詞implements聲明的繼承只繼承接口
這種繼承有時被稱作Sub
typing
在UML中
實現接口的類與接口定義之間的關系叫做Realization關系
用一個虛線封閉箭頭表示
從實現接口的類指向接口
接口本身的UML圖與普通類一樣
但它的名字上面要加上
<
>圖四由圖一修改而成Payment類被一個接口取代(關於Realization名稱的說明Realization最常見的中文譯名是實現但是Java的implements也叫做實現為避免混淆本文中凡是出現Realization的地方一律直接使用英文)
圖四接口與實現接口的類之間的Realization關系
接口可以從一個或者多個其他接口擴展UML一般化關系(實線封閉箭頭)可用來描述這種關系如圖五所示
圖五UML一般化關系用來表示一個接口擴展了一個或者多個其他接口
UML還支持另一種接口符號即用圓圈表示接口(加上連線之後就成了棒棒糖的樣子)但這種表示法多用於UML組件圖在UML類圖中比較少見
如果UML圖規模較大有大量的類實現一個常用接口整個UML圖可能亂成一團糟《Java Design》一書提出了一種簡化方法後來又被《Streamlined Object Modeling》一書的作者采用這就是在實現接口的類中用接口的名字替代從接口繼承的方法不過這不屬於標准方法遺憾的是目前似乎還沒有工具支持這種轉換圖六是用Together ControlCenter工具加工出來的簡化類圖
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27335.html