關係
物件透過訊息(message)的傳遞至另一個物件,救代表了兩個物件之間,建立一種連線(link)的關係。觀察一段敘述:韓劇中的長今,因為當醫女要練習針灸的緣故,所以施針在一隻大頭吉娃娃身上。以 UML 物件圖(Object Diagram) 來表示如下圖:
圖1、範例—物件之間的連結關係
上圖 1 的箭頭表示物件的可視性(visibility),說明長今(UML 物件圖內的物件名稱係加上底線表示之))物件傳送了 “針灸” 訊息給大頭吉娃娃物件。箭頭是否有可能為雙向? 當然有可能!例如,大頭吉娃娃因為被扎針後很痛而反過來咬了長今一口,如此兩個物件就構成了雙向關係,參考如下圖:
圖2、範例—物件之間的雙向連結
觀察物件之間的關係,再予以抽象化(abstract),也就是說再進而一步地來觀察這些物件所屬類別(class)之間的關係,依據其關係的性質與其結構性,可以發掘出類別之間的關係,分為三種:
- 關連(Association)
- 組成關係(整體—局部,Whole-parts)
- 一般化—特殊化(Generalization—Specialization)
針對上述三種類別之間的關係,有必要個別來作詳細說明,並列舉範例、UML 語法與範例程式碼等。
結合關係(Association)
說明
「連結(link)」表示物件之間的關係;而「結合(association,或翻譯為關連)」就是將物件之間的「連線」關係抽象化,用來表示類別與類別之間的抽象關係。
結合代表著我們需要記憶類別之間的關係,通常是在某個情境當中,我們需要保存其相關資訊一段時間(視領域與需求而定,一般而言,可能保持幾秒到數十年的情況都有可能)。例如,以 「人(Persion)」與「狗(Dog)」這兩個類別來看,兩個類別是否有關係?若是我們塑模(Modeling)的對象為寵物店(Pet Shop)管理系統,那麼顯然這兩個類別就有值得保存兩者之間關係的必要性;但若開發的對象為人事管理系統,那麼,你又何必將「狗」這個類別與「人」類別關連起來,甚至,根本就沒有必要將「狗」類別給塑模包含至人事管理系統來的。
關於結合關係的 UML 表示法如下圖:
圖3、範例—結合關係的UML表示語法
在結合關係內的每一個類別,都有其各自所擔任的角色(role),參考上圖 3,「Person」類別在與「Company」類別的結合關係中,是擔任了 “雇員” 的角色;反之,「Company」類別則是擔任著在這個結合關係中的 ”雇主” 角色,類別所擔任的角色,是表示在這個關連靠近類別的端點旁邊。
關連也可以為其命名,來凸顯兩個類別之間的一種行為。上圖 3的關連名稱被命名為 “雇用契約”,代表著「Person」類別與「Company」類別是一種 “雇用” 的結合關係。
範例
範例—駕駛員與汽車的結合關係
觀察周遭生活面面向,可以舉出太多一般性的類別與類別之間的結合關係。例如,”人開著汽車”,以這麼簡短的一句話,將其抽象化,就可以發現到,有兩個主要的類別:「人」與「汽車」,兩者必然存在著關係,否則,車子如何有可能會發動、行進呢?
UML 表示法
圖4、範例—Driver與Car 類別的關連UML表示法
上圖 4表達了「Driver」類別與「Car」類別的 UML 表示法,其中,1 對 1…* 為多重性(multiplicity)的表示法,多重性定義了類別 A 會有多少個個體(instance)與類別 B 多少個個體會關連在一起。,上圖的多重性定義即表示為:一個駕駛員可以擁有1到多台車子。
Hint: 如何找出 “Car” 類別的屬性與操作?
從車子的角度來思考,車子應該知道什麼資訊(Knowing),以及應該負責那些行為(Doing)。請仔細的觀察,當你在開車時,你所看到的儀表板數據就是車子所應該知道的資訊,這些資訊就會成為「Car」類別的屬性;你所操作車子的動作,包括啟動、排檔、踩油門、轉動方向盤、煞車…等,就是車子所提供給駕駛的服務(service),也就是「Car」類別的操作(在程式語言的術語則稱為 “method”)。
Java 程式範例碼
#001 public class Driver { #002 #003 private String name; #004 private String 行照號碼; #005 public Car m_Car; #006 #007 public String getName(){ #008 return "駕駛員名稱:" + name; #009 } #010 #011 public String get行照號碼(){ #012 行照號碼 = "XXXX-XXXX-00128"; #013 return 行照號碼; #014 } #015 }
#001 public class Car { #002 #003 private String 型號; #004 private String 車號; #005 private float 里程數; #006 private int 油表數; #007 #008 public float get里程數(){ #009 //需至里程記錄器取得資料 #010 里程數 = 58000; //先給個測試數值 #011 return 里程數; #012 } #013 #014 public int get油表數(){ #015 油表數 = 12; //剩餘 12 公升 #016 return 油表數; #017 } #018 #019 public String get車況資訊(){ #020 型號 = "蛋龜二號"; #021 車號 = "GY-8228"; #022 String 車況 = "型號:" + 型號 #023 + ";車號:" + 車號; #024 return 車況; #025 } #026 #027 public String 踩油門(){ #028 return "動作: 踩油門"; #029 } #030 #031 public String 排檔(String 排檔別){ #032 return "動作: 排檔-> " + 排檔別; #033 } #034 #035 public String 開啟(){ #036 return "動作: 開啟"; #037 } #038 #039 public String 煞車(){ #040 return "動作: 煞車"; #041 } #042 #043 public String 關閉(){ #044 return "動作: 關閉"; #045 } #046 #047 public String 轉動方向盤(){ #048 return "動作: 轉動方向盤"; #049 } #050 }
為了測試 “Car” 類別所提供的 method,我們可以先設計一個測試用的 Java stand-alone 的程式,以站在 “Driver” 的角度,來看車子的操作:
#001 public class TestCar { #002 public static void main(String[] args) { #003 Car m_car = new Car(); #004 #005 System.out.println(m_car.開啟()); #006 System.out.println(m_car.排檔("D")); #007 System.out.println(m_car.踩油門()); #008 System.out.println(m_car.get油表數()); #009 System.out.println(m_car.get里程數()); #010 System.out.println(m_car.關閉()); #011 } #012 }
執行結果如下:
動作: 開啟 動作: 排檔-> D 動作: 踩油門 12 58000.0 動作: 關閉
這裡定義了Driver卻沒有使用,請問定義它的意義是什麼?
Hi, Client 代表了 Driver,此處範例簡化了。
該程式碼的下載可參考:
https://www.facebook.com/groups/softthinking/
寫得真的超級超級棒
還搭配上範例程式碼!!!
真的十分感謝您的貢獻
您可以參考:
https://www.facebook.com/groups/softthinking/files/
簡報檔案&程式碼範例均免費提供下載的。 🙂
Hello 生魚片:
因為我以為這是 “common sense”,所以沒多說。 ^^
看來對這樣從類別圖對應到程式碼的實作呈現,我應該要多弄一些程式碼範例與解說囉。 >_@
由於 Driver 與 Car 的多重性為一對多,所以在Driver的實作上會用Collection來存放Car這個物件。