我經常在說,如果要票選第一重要的UML圖的話,我一定會選類別圖。類別圖主要用來在表達系統內部的靜態結構,系統內部的靜態結構重大影響了日後系統是否能夠承受的起多元的變動,包括企業流程的變動、企業概念的變動、企業規則的變動、實體技術平臺的變動、資料庫的變動、程式語言的變動等等。

也因此,我個人認為類別圖是最難設計的好的一款圖,也是最需要花功夫學習和練習的一款圖,同時它也是UML圖中涵蓋最多概念的一款圖。關於類別圖的指南編號從87到145,共計有五十九條為原著書中所有章節之冠,分為六個小節:一般性指南、類別風格、關係、結合關係、繼承關係、聚合與組合關係。

一般性
類別圖適合用來表達各層面的靜態結構,常見如需求階段的領域模式(domain model)、分析階段的分析模式(analysis model)、或者是設計階段的設計模式(design model),都可以見到類別圖的身影。所以,在此小節的一般性指南中,編號從87到94共計八條的指南,便是在說明跟各層面類別圖有關的指南。

指南87 在領域類別模式中,專注辨識出「責任」就好(Identify Responsibilities on Domain Class Models)
在領域類別模式中,重點在類別以及類別所擔負的「責任」(responsibility),具體的屬性或操作在領域類別模式中決定。
比方說,訂購交易類別有責任提供訂購總金額,但是到底要用什麼方法提供,是定義一個名為總金額的屬性來保存總金額,還是設計一個計算總金額的操作來即時算出,則不在領域類別模式中決定,如圖1所示。


指南88 只有在設計模式中,才指定「能見度」(Indicate Visibility Only on Design Models)

指南89 跟程式語言有關的能見度,可以標示在「性質字串」中 (Indicate Language-Dependent Visibility with Property Strings)
能見度(visibility)通常用來表達屬性和操作的存取等級,UML設置了四種能見度,分別為:公開(public)、私有(private)、保護(protected)和套件(package)四種能見度。

公開和私有能見度最常見,也最容易懂。請看圖2的例子,存戶類別的屬性能見度是私有等級(private),操作為公開等級(public)。減號(-)為私有能見度,加號(+)為公開能見度。


公開等級的能見度就像透明的車窗玻璃,所有類別都可以視見。不過,私有等級則恰好相反,它像反光玻璃只有由同類別才可以視見。請看下面圖3的例子,帳戶類別可以看見存戶類別裡的公開操作,但是,無法視見存戶類別的私有屬性。


私有能見度滴水不漏,就連子類別也無法視見父類別的私有成員,這樣其實不利於繼承機制,如圖4所示。


所以,UML設置保護(protected)等級的能見度,特別開放子類別可以視見父類別的保護成員(protected member),以便提供更方便的繼承機制。保護能見度的符號是井號(#),如圖5所示。


至於套件(package)能見度,顧名思義,它是為了套件而設置的,它的符號是否定號(~),如圖6所示。同套件的元素,可以視見其他元素內部的套件成員。所以,從圖6中,我們可以得知帳戶可以視見存戶類別的姓名和電話,但是分行(branch)卻無法視見,只因為分行不是同套件裡頭的成員。


由於,UML僅提供四種能見度,所以要想標示其他的能見度的話,可以標示在「性質字串」(property string)中。譬如,C++有一種「友朋」(friend)等級的能見度,這是UML所沒有的,可以標示在性質字串的大括號中,如圖7所示。

指南90 只有在該型別為實際需求時,才在分析模式中指定之(Indicate Types on Analysis Models Only When the Type Is an Actual Requirement)

指南91 注意屬性名稱與型別的一致性(Be Consistent with Attribute Names and Types)
有時候,資料型別是需求的一部分。比方說,永豐銀行帳號為十四碼數字、銀行代碼為三碼數字、分行代碼為四碼數字,這些號碼都是數字而且個數數目固定,開發人員不能自行做決定,它們是需求的一部分。原著作者建議我們,只有在資料型別為需求的一部分的情況下,才在分析模式中指定屬性的資料型別。

另外,如果在屬性名稱中有暗示型別的話,最好暗示的型別跟真正的型別一致。例如,

● 顧客「號碼」(customerNumber)—「號碼」暗示著數字,所以顧客號碼的資料型別直覺為「整數」。

● 顧客「代碼」(customerID)—「代碼」暗示為數字或字串,所以顧客號碼的資料型別可能是「字串」或「整數」。

也就是說,如果該屬性的資料型別為整數的話,將它命名為「顧客號碼」會較佳;若為字串的話,則命名為「顧客代碼」。

指南92 在分析圖中,建立「結合類別」(Model Association Classes on Analysis Diagrams)

指南93 如果結合關係已經表達成結合類別的話,就別再為該結合關係命名了(Do Not Name Associations That Have Association Classes)

指南94 結合類別的虛線,連接到結合關係線的中間(Center the Dashed Line of an Association Class)
「結合類別」(association class)的概念不是一個很普及的概念,如果以UML官方的三級認證考試來看,它被歸屬於高級認證的考試範圍,所以在談這三條指南之前,我想先來補充一點結合關係的概念。

如果,兩物件因為結合關係而延伸出相關的屬性與操作,而且不適合將這些屬性及操作歸給任一結合端的類別時,可以讓結合關係擴大為結合類別,以便享有類別的特質。

比方說,兩人結婚之後,有了婚姻關係,如圖8所示。婚姻關係本身會延伸出像是結婚時間、地點、證婚人等等的屬性項目,以及相關的操作,這些似乎不適合歸給個人類別。


在這種情況下,我們可以將圖8裡的結合關係,延伸成具有類別特質的結合類別,如圖9所示。以虛線連接類別及結合關係,這個類別即為結合類別。


請看圖10的物件圖,有了婚姻連結有了對應的物件之後,便可以持有相關的屬性數值。


由於,一條連結對應一個結合物件,所以一旦兩物件之間會發生多次連結,且必須留下每一個結合物件時,就得小心使用結合類別的概念。比方說,會員訂購商品的情況,若將訂購設計成結合類別時,恐怕無法留下兩者之間所發生過的所有訂購物件。請看圖11的設計,僅能保留最新的訂購資料。


如果,想要能夠保有訂購的歷史資料的話,其中一種設計是將圖11改成圖12。結合類別跟一般類別沒什麼不同,一般類別具備的所有特質,結合類別也都具有。


請看圖13的物件圖,即便同一名會員多次訂購相同的商品,也能留下歷史訂購資料。


不過,當某個會員退會了或某種商品下架了,兩者之間的訂購交易就不復存在了。如果,我們把訂購交易視為一項重要的事件,不想因為會員或商品的不復存在而磨滅訂購交易曾經發生過的事實的話,恐怕就不適合將訂購設計為結合類別了。針對這個問題,我們可以把訂購類別改成一般類別,如圖14所示。


或者,再增加一個訂購次項類別,讓每一個訂購次項物件對應一種商品物件,去除圖14中訂購與商品多對多的個體數目情況,簡化實作多對多的複雜度,如圖15所示。

最後,我們再回過頭來看編號92到94的三條指南。原著作者認為在分析圖中可以使用結合類別,我倒是不這麼認為,我認為能少碰它就少碰,畢竟結合類別的概念不是一個普及或初學者該學的概念,使用的人少,用起來成本也高。

再者,程式語言也沒有支援,分析階段如果用了結合類別,到了設計階段還得額外想個機制來支援結合類別,老話一句,成本太高。
所以,除非是非用它不可,否則我不建議使用,不過到目前為止,在我的實務經驗中,從來也沒出現過非用它不可的情況。

由於,結合關係與結合類別兩者為相同的東西,只不過前者不具備類別特質,所以如果已有結合類別,當然就不需要再為結合關係命名了。一般結合關係的名稱擺在結合關係線旁,如圖16所示,用來說明其兩端類別的關係為何。


為求圖面整齊,結合類別的虛線盡可能連接到結合關係線的中間,總之再把格線底稿的方法搬出來,就可以讓圖面上的節點整齊劃一,如圖17所示。


類別風格
此處跟類別有關的指南,編號由95到111,一共有十七條。不過,這十七條指南都很好懂,不用花什麼時間,一口氣就可以把它們讀完了!

指南95 使用一般性術語做為類別名稱(Use Common Terminology for Class Names)


指南96 最好使用完整的單數名詞做為類別名稱(Prefer Complete Singular Nouns for Class Names)

指南97 使用強動詞做為操作名稱(Name Operations with Strong Verbs)

指南98 使用領域相關的名詞做為屬性名稱(Name Attributes with Domain-Based Nouns)

編號第95條指南中提到,使用一般性術語做為類別名稱,可以增強理解與溝通,這我就不多做解釋了。

編號第96條指南中,所謂的「完整的」是指少用縮寫字,例如「顧客」就乖乖用“customer”英文字,最好別用“cust”的縮寫字,理由同樣是為了便於理解與溝通。

至於,編號97和98中的操作名稱用動詞、屬性名稱用名詞,這是因為操作記錄了物件的動態行為,而屬性則記錄了物件的靜態資料,所以直覺上,我們習慣用動詞命名操作,用名詞命名屬性。

指南99 別建立「鷹架碼」(Do Not Model Scaffolding Code)
建築鷹架不是建築物的主體,通常是支撐用途,用完就拆。顧名思義,「鷹架碼」(scaffolding code)就類似建築鷹架,這類的程式碼通常不是主要的程式碼,但主要的程式碼需要靠它們來支撐,雖然事後不會真的像建築鷹架一樣用完就拆。

譬如,屬性的存取操作、物件的建構式(constructor)及解構式(destructor)是最常見的鷹架碼。一開始建立類別圖時,其實根本不需要花時間去建立這些可有可無的操作,甚至多數的UML工具都可以依據屬性及類別自動產生存取操作、建構式及解構式。

指南100 類別名稱置中(Center Class Names)

指南101 屬性和操作名稱靠左(Left-Justify Attribute and Operation Names)
編號第100和101這兩條無聊的指南跟版面有關,沒什麼偉大的理由,就只是多數人的習慣,總之就是類別名稱置中、屬性和操作名稱靠左。

指南102 別建立「鍵值」(Do Not Model Keys)
熟知「關聯式資料庫」(relational database)的開發人員都知道,必須設置資料的「鍵值」(key)才能夠執行兩個表格之間的連結。倘若,我們改用UML類別圖來表達資料結構時,其實是不需要在類別中設置鍵值的。

鍵值是關聯式資料庫的機制,它不是物件導向概念。事實上,在具備物件導向特色的UML類別圖中,我們只要透過結合關係就可以連結兩種物件,不需要藉助鍵值。

指南103 避免只顯示兩格類別(Never Show Classes with Just Two Compartments)

指南104 標示出非一般性的類別格(Label Uncommon Class Compartments)UML預設的類別圖示是三格矩形,從上而下依序放置類別名稱、屬性、操作,也可以將屬性格和操作格隱藏起來,只秀出類別名稱,但是避免只秀出兩格矩形,如圖18所示。


除了預設的類別名稱、屬性和操作的三格之外,UML也允許我們自行擴充格子放置額外的資訊。例如圖19,除了預設的三格之外,我們額外增加了責任格、事件格和限制格。不過雖說如此,多數的UML工具可以讓使用者填寫其他的資訊,但沒有提供秀出多格矩形的功能。


指南105 未完成列的最後一列可放置「省略號」(Include an Ellipsis (…) at the End of an Incomplete List)
除了放置類別名稱的頂格外,其餘放置屬性、操作或其他額外資訊的格子中,都可以使用「省略號」(…)來標示該格的內容不完整,部分資訊省略了並未列出,如圖20所示。


指南106 靜態操作/屬性條列於個體操作/屬性之前(List Static Operations/Attributes Before Instance Operations/Attributes)
靜態(static)屬性或操作,也稱為「類詞層級」(classifier-level)的屬性或操作,相對的,一般的屬性及操作則稱為「個體層級」(instance-level)的屬性或操作。簡單來說,如果該屬性或操作為類別所有,即為靜態屬性或操作,若為物件所有則為一般的屬性或操作。

通常,我們沒有特別說明的屬性及操作都屬於個體層級;至於,用來誕生物件的建構式,或者是用來消滅物件的解構式,則是最常見的靜態操作。請看圖21,靜態屬性或操作的名稱有底線,一般個體層級的屬性或操作的名稱是沒有底線的。


指南107 依照能見度遞減的順序放置操作/屬性(List Operations/Attributes in Order of Decreasing Visibility)
能見度的遞減順序應該依序為:公開、套件、保護、私有,除了使用加號(+)、否定號(~)、井號(#)和減號(-)之外,也可以使用能見度的字眼依序分群條列屬性或操作,如圖22所示。


指南108 針對物件參數,僅條列出它們的型別(For Parameters That Are Objects, List Only Their Types)
為了節省圖面空間,所以無論是輸入或輸出的物件參數,皆標示出它所屬的類別型別即可,其餘非物件參數才標示出它的參數名稱,如圖23所示。
指南109 使用一致性的操作與屬性簽名(Develop Consistent Operation and Attribute Signatures)
在操作或屬性的命名上,盡量講求一致的風格。例如圖24的訂購交易類別,只要是跟「新增」(create)有關的操作,其操作名稱全都以「新增」為首,像圖中的新增訂購交易、新增訂購次項。這樣一來,命名的風格一致、名稱整齊劃一,便於溝通與理解。


指南110 程式語言命名慣例可以表達的資訊,別濫用「模版」重複表達相同的資訊(Avoid Stereotypes Implied by Language Naming Conventions)
「模版」(stereotype)是UML很常見且重要的擴充機制,它可以讓我們添加額外的資訊。模版放置於雙角括號內(《》),如圖25的範例中,我們可以透過《Java》來標示出顧客類別是一個Java類別。


但是,千萬別濫用模版來表達程式語言命名慣例可以隱含的資訊。比方說屬性的存取操作,我們通常會用「設定」某某(setXX)、「取得」某某(getXX)的命名方式,這時就別再多此一舉,濫用《setter》或《getter》模版了,如圖26所示。


指南111 使用操作的性質字串指出例外控制(Indicate Exceptions in an Operation’s Property String)
多數的程式語言都有例外控制的機制,在條列操作時,我們可以將例外控制標示於性質字串的大括號內,如圖27所示。


類別圖的UML指南是Scott W. Ambler原著中篇幅最多的一個章節,到目前為止,已經介紹了25條類別圖的UML指南,包括了8條「一般性指南」,以及17條「類別風格」指南。

在下一期將繼續介紹剩下的24條類別圖的UML指南,從「關係」開始談起,這是在類別圖中,除了類別以外的另外一個重要的概念。

此外,也針對「結合關係」、「繼承關係」、「聚合與組合關係」等,一一介紹繪製這些關係線時,可以參考的UML指南。


Amazon UML暢銷書排行榜


Head First Object-Oriented
Analysis and Design

作者:Brett D.
McLaughlin,
Gary Pollice,
Dave West
出版時間:2006.11.1
出版社:O'Reilly

UML for the IT Business
Analyst: A Practical Guide to
        Object-Oriented
        Requirements Gathering

作者:Howard
Podeswa
出版時間:2005.6.7
出版社:Course
Technology

UML Distilled: A Brief Guide
to the Standard Object
  Modeling Language(第三版)

作 者:Martin Fowler
出版時間:2003.9.25
出版社:Addison-
Wesley

The Rational Unified Process
Made Easy: A Practitioner's
        Guide to the RUP

作者:Per Kroll,
Philippe
Kruchten
出版時間:2003.4.18
出版社:Addison-
Wesley

Learning UML 2.0

作者:Russ Miles, Kim
Hamilton
出版時間:2006.4.25
出版社:O'Reilly

Applying UML and Patterns: An
Introduction to Object-Oriented
        Analysis and Design and
        Iterative Development(第三版)

作者:Craig Larman
出版時間:2004.10.30
出版社:Prentice Hall

UML Distilled: A Brief Guide
to the Standard Object
        Modeling Language(第三版)

作者:Martin Fowler
出版時間:2003.9.25
出版社:Addison-
Wesley


作者簡介:
邱郁惠
研究OOAD、UML、MDA十餘年,經歷過顧問、專案、教學及寫作工作。離職後創辦UML Blog推廣UML,組織《UML互助會》社群定期舉辦軟體技術講座,出版多本UML專業書籍與電子書。目前擁有OCUP/UML三級認證、PMP認證。

相關連結─
沒時間讀 UML/OOAD 書之挑讀筆記 第6回 The Elements of UML 2.0 Style(1)
沒時間讀 UML/OOAD 書之挑讀筆記 第7回 The Elements of UML 2.0 Style(2)
沒時間讀 UML/OOAD 書之挑讀筆記 第8回 The Elements of UML 2.0 Style(3)
沒時間讀 UML/OOAD 書之挑讀筆記 第9回 The Elements of UML 2.0 Style(4)

熱門新聞

Advertisement