準則: 設計類別
設計類別代表直接對映於程式碼的設計元素。這個準則說明如何開發「設計類別」。
關係
主要說明

定義

設計類別代表系統實作中一或多個類別的抽象化;它確切的對應項目會隨著實作的語言而不同。例如,在物件導向語言(如 C++)中,類別可以對應於一般類別。在 Ada 中,類別可以對應於套件的可見部分所定義的標示類型。

類別用來定義物件,物件則用來實現(實作)使用案例。類別起源於「使用案例實現化」在系統需要的物件上所設定的需求,以及先前所開發的任何物件模型。

類別好不好主要取決於實作環境。比方說,類別及其物件的適當大小會隨著程式語言而不同。對 Ada 而言是正確的情況,當使用 Smalltalk 時,便可能是錯誤。類別應該對映到實作語言中的特定現象,且類別應該結構化,對映才能產生好的程式碼。

雖然實作語言的特性會影響設計模型,但類別結構必須很容易理解和修改。您在設計時,應該假設具有類別和封裝,即使實作語言並不支援。

作業

物件只能利用另一個物件的作業來存取或影響它的屬性或關係。物件的作業由它的類別來定義。特定行為是用作業來執行的,作業可以影響物件所擁有的屬性和關係,且可以造成執行其他作業。作業對應於 C++ 中的成員函數,或 Ada 中的函數或程序。將什麼行為指派給物件,取決於它在「使用案例實現化」中所扮演的角色。

參數

在作業規格中,參數構成形式參數。每個參數都有名稱和類型。您可以利用實作語言的語法和語意來指定作業及其參數,以便在開始撰寫程式碼時,它們已指定在實作語言中。

範例:

回收機系統中,Receipt Basis 類別的物件會追蹤客戶投入多少特定類型的存放項目。Receipt Basis 物件的行為包括增加回收物件的數目。insertItem 作業負責接收指向投入項目的參照,它會實現這個目的。

圖解說明詳見隨附的文字。

當指定作業時,請使用實作語言的語法和語意。

類別作業

作業幾乎一律是指物件行為。但作業也可以表示類別的行為,這時它是一項類別作業。您可以在 UML 中,設定作業的類型範圍來建立這個模型。

作業可見度

以下是作業可能有的可見度:

  • Public:類別本身以外的模型元素都可以見到作業。
  • Protected:只有類別本身及其子類別,或類別的伙伴(這會隨著語言而不同),能夠見到作業。
  • Private:只有類別本身及類別的伙伴能夠見到作業。
  • Implementation:只在類別本身以內能夠見到作業。

Public 可見度的使用應該非常保守,只在另一個類別需要這個作業時才使用。

Protected 可見度應該是預設值;它會保護作業,使外部類別無法使用它,這會促成寬鬆的行為耦合性和封裝。

Private 可見度應該用在不讓子類別繼承作業之時。這可用來將子類別和超類別解除耦合,減少移除或排除未用之繼承作業的需求。

Implementation 可見度最嚴格;當只有類別本身可以使用作業時,便使用這個可見度。它是 Private 可見度的變式,大部分類別都適用。

狀態

物件可以根據它的狀態,用不同方式來反應特定訊息;物件相依於狀態的行為由相關聯的狀態圖來定義。對於物件能夠進入的每個狀態,狀態圖會說明它能夠接收的訊息、將實現哪些作業,以及物件後來會在什麼狀態中。請參閱技術:狀態圖,以取得詳細資訊。

協同作業

協同作業是一組動態的物件互動,在這組互動中,一組物件藉由互相傳送訊息來通訊。在 Smalltalk 中,訊息的傳送很簡單;在 Ada 中,它是作為一項子程式呼叫來完成的。訊息會傳給在物件內呼叫作業的接收端物件。這個訊息會指出要執行的作業名稱,以及所需要的參數。當傳送訊息時,會針對所有參數來提供實際參數(形式參數的值)。

互動圖說明「使用案例實現化」內各物件之間的訊息傳輸,以及呼叫作業時物件所遵循的控制焦點。請參閱技術:序列圖技術:通訊圖,以取得這些圖的相關資訊。

屬性是物件的具名內容。屬性名稱是關聯於物件來說明屬性角色的名詞。當建立物件時,屬性可以有起始值。

您只應在建立屬性模型有助於理解物件時,才建立屬性模型。只有在物件內容是這個物件單獨擁有的內容時,您才應該將這個內容的模型建立成一個屬性。否則,您應該利用關聯或聚集關係(指向其物件代表這個內容的類別)來建立這個內容的模型。

範例:

圖解說明詳見隨附的文字。

如何建立屬性模型的範例。每個家庭成員都有名稱和地址。在這裡,我們分別識別了 NameAddress 類型的 my namehome address 屬性:

圖解說明詳見隨附的文字。

這個範例利用關聯來取代屬性。對家庭的每個成員來說,my name 內容大概都是唯一的。因此,我們可以將它的模型建立成 Name 屬性類型的一個屬性。不過,所有家庭成員都會共用地址,因此,它最好利用 Family Member 類別和 Address 類別之間的關聯來建模。

要將某概念的模型建立成個別物件,或建立成另一個物件的屬性,並不一定能當下輕易決定。物件模型中多餘的物件會帶來不必要的文件和開發成本。因此,您必須建立特定的準則來判斷概念在系統中的重要性。

  • 可存取性。支援您選擇物件或屬性的,並不是概念在真實世界中的重要性,而是在使用案例期間需要存取它的程度。如果經常存取這個單元,請將它的模型建立成物件。
  • 在執行期間區分。建立將使用案例當作物件來執行期間個別處理的概念模型。
  • 關聯於其他概念。建立嚴格關聯於某些其他概念且絕不分開使用(但一律是透過物件,作為物件的屬性來使用)的概念模型。
  • 關係的需求。如果您為了某些原因,必須從兩個方向來建立某單元的關係,請重新檢查這個單元,看它是否應該是獨立物件。兩個物件不能關聯屬性類型的同一個實例。
  • 出現頻率。如果單元只在某使用案例期間存在,請勿將它建立成物件模型。相反地,請將它的模型建立成執行相關行為之物件的屬性,或只是在受影響之物件的說明中提及它。
  • 複雜度。如果物件因屬性而成為太複雜,您也許可以將部分屬性擷取在獨立物件中。不過,這個動作要有節制,以免有太多物件。另一方面,這些單元也可能非常簡單。例如,分類為屬性的有 (1) 單元和 (2) 單元。(1) 單元夠簡單,實作語言的初始類型便足以直接支援它們,例如 C++ 中的整數;(2) 單元也夠簡單,利用獨立於應用程式之外的實作環境元素便可以實作它們,例如 C++ 和 Smalltalk-80 中的 String

您可能會針對不同系統,用不同方式來建立概念模型。在某個系統中,這個概念可能非常重要,以致於您會將它的模型建立成物件。但在另一個系統中,它可能比較不重要,您便將它的模型建立成物件的屬性。

範例:

比方說,如果是航空公司,您會開發一個支援出境的系統。

圖解說明詳見隨附的文字。

支援出境的系統。假設機場人員需要一個支援出境的系統。對於每一次出境,您都必須定義出境時間、航空公司及目的地。您可以將它的模型建立成 Departure 類別的物件,含有 time of departureairlinedestination 等屬性。

相反地,如果系統是為了旅行社而開發的,狀況會有些不同。

圖解說明詳見隨附的文字。

航班目的地會形成它自己的 Destination 物件。

當然,仍會需要出境時間、航空公司和目的地。不過,這時還有其他需求,因為旅行社感興趣的出境項目有特定目的地。因此,您必須專為了 Destination 而建立一個獨立的物件。當然,DepartureDestination 的物件必須互相知道對方,這是藉由其類別之間的關聯來完成的。

代表特定概念重要性的引數也有效,可用來判斷應該在類別中定義哪些屬性。如果 Car 類別的物件是汽車登錄系統的一部分,而非汽車製造系統的一部分,它當然會定義不同的屬性。

最後,什麼將呈現為物件,什麼將呈現為屬性,這項規則並非絕對。在理論上,每個項目的模型都可以是物件,但這很笨重。簡單的基本原則是將物件看成在某個階段使用時,與其他物件無關。另外,您也不需要利用屬性來建立每個物件內容的模型,只有必須用來瞭解物件的內容才需要。凡是會隨著實作而非常不同,因而最好由實作者來處理的細節,您都不應該建立它們的模型。

類別屬性

屬性幾乎一律是指物件內容。但屬性也可以表示類別的內容,這時它是一項類別屬性。您可以在 UML 中,設定屬性的類型範圍來建立這個模型。

建立含屬性的外部單元模型

物件可以封裝一些它不需要執行任何行為,就可以改變值的東西。這可能實際上是外部單元,模型卻未建立成參與者的東西。例如,在選擇系統界限之後,界限之間可能會有某種形式的感應器設備。之後,就可以將感應器封裝在物件內,利用它測量的值來構成屬性。之後,就可以物件在不受系統任何其他物件影響的情況下,連續變更這個值,或依固定間隔來變更這個值。

範例:

您可以將溫度計的模型建立成物件;這個物件有一個代表溫度的屬性,且會變更值來回應環境溫度的變更。其他物件可以執行溫度計物件的作業來要求目前的溫度。

圖解說明詳見隨附的文字。

Thermometer 物件內,temperature 屬性的值會自發地改變。

您仍可以將這個方式所變更的封裝值建立成一般屬性的模型,但您應該在物件類別中說明它是自發地變更。

屬性可見度

屬性可見度假設下列其中一個值:

  • Public:在類別所在的套件內外,都能見到這個屬性。
  • Protected:只有類別本身及其子類別,或類別的伙伴(這會隨著語言而不同),能夠見到這個屬性。
  • Private:只有類別本身及類別的伙伴能夠見到這個屬性。
  • Implementation:類別本身能夠見到這個屬性。

Public 可見度的使用應該非常保守,只在另一個類別會直接存取這個屬性時才使用。定義 public 可見度實際上是將屬性可見度定義成 protected、private 或 implementation 的速記表示法,以相關聯的 public 作業來取得及設定屬性值。Public 屬性可見度可用來作為一項宣告,告訴程式碼產生器應該自動產生這些取得/設定作業,以在類別定義期間節省時間。

Protected 可見度應該是預設值;它會保護屬性,使外部類別無法使用它,這會促成寬鬆的行為耦合性和封裝。

Private 可見度應該用在不讓子類別繼承屬性之時。這可用來將子類別和超類別解除耦合,減少移除或排除未用之繼承屬性的需求。

Implementation 可見度最嚴格;當只有類別本身可以使用屬性時,便使用這個可見度。它是 Private 可見度的變式,大部分類別都適用。

內部結構

有些類別可以代表複雜的抽象化,且有複雜的結構。當建立類別的模型,設計者可以呈現它的內部參與元素及其關係,以確保實作者會據此實作這個類別內所發生的協同作業。

在 UML 2.0 中,類別定義為結構化類別,它可以有內部的結構和埠。之後,類別可以拆解成相連組件的集合,這些組件又可以進一步拆解。強制來自類別外的通訊遵循宣告的介面來通過埠,便可以將類別封裝起來。

因此,除了利用類別圖來呈現類別關係(如關聯、組合和聚集)和屬性之外,設計者也可以使用組合結構圖。這個圖提供一種機制,供設計者顯示內部組件的實例如何在給定類別的實例內扮演它們的角色。

如果需要這個主題的詳細資訊及組合結構圖的範例,請參閱概念:結構化類別