台灣最大程式設計社群網站
線上人數
2568
 
會員總數:245250
討論主題:189111
歡迎您免費加入會員
討論區列表 >> 專欄文章 >> 類別之間的關係(Relationship) — 一般化—特殊化 —Basic
[]  
[我要回覆]
回應主題 加入我的關注話題 檢舉此篇討論 將提問者加入個人黑名單
類別之間的關係(Relationship) — 一般化—特殊化 —Basic
價值 : 0 QP  點閱數:1111 回應數:0

樓主

Kenming
初學者
20 53
874 3
發送站內信

說明

從生活面的觀點來觀察時,當發現到兩個以上的類別有其相似之處(但又不盡相同),我們可以把相似之處抽象(abstract)放在更高層次的一般性類別。例如,觀察「貓」與「狗」兩個類別,是否有可能抽象化成為一般性的類別? 兩者的品種完全不同,但其實也存在著某種程度的相似性,事實上,若我們要開發一個 “寵物店管理系統”,那麼,其實很自然,就可以將此兩個類別抽象成為「寵物」這個一般化的類別。相對來說,只要是符合「寵物」一般化類別共同特性的其它類別,包括可愛、能取悅、陪伴主人等特徵與行為,就可以成為「寵物」的特殊化類別。一般化—特殊化關係的 UML 表示法如下圖。



圖1、範例 一般化—特殊化的 UML 表示法


概念上,所有貓、狗的個體(instances)從定義來看也都是「寵物」的個體,那麼就可以將「貓」、「狗」等視為是「寵物」的子型態(sub-type)。由此可以看出,「貓」是一種特別的「寵物」。其中一個重要的觀念在於,所有與「寵物」有關係的特徵(features),包括關連、屬性(attributes)與操作(operations),對「貓」、「狗」、「烏龜」來說也都是成立的。

從軟體的觀點來看,對一般化關係的具體實作就是 “繼承(inheritance)” : 「貓」是「寵物」的子類別(sub-class),在主流的 OOP 語言,包括 Java 與 .NET 等,子類別會繼承超類別(super-class)的所有特性,而且還可以覆寫(override)任何超類別的方法(method)。

一般程式設計人員最容易誤解物件導向的繼承觀念就在於,以為繼承是被用來 “可重用(re-use)”的:可重用既有的程式碼。其實繼承的最重要原則是在於 “可被替代性(substitutability)”,而這正是物件導向另一個非常重要的思維– “多型(polymorphism)”:讓外界(Client)能以「一視同仁」的角度來看待多個特殊化類別所抽象出的一般化類別!

關於 "多型" ,留待在進階主題內再行詳述。請記得,多型同時也是解決軟體複雜度的一個重要原則。

範例—車子的一般化—特殊化類別

UML 表示法


圖2、圖2、範例—範例—車子的一般化—特殊化 UML 表示


卡車、坦克車、悍馬車,都是屬於 “車子” 的特殊化類別。特殊化類別均具有 “車子” 的共同特性,但也可以 “修正” 與 “擴展” 一般化類別的行為。以上圖為例,卡車可以 “超載(override)” “車子” 的 “get車況” 這個操作;同時又 “擴展(extend)” 了原來 “車子” 所沒有的行為: “裝載物資”。 事實上,當從一般化類別的角度來看時,設計人員是因為需要 “修正(也就是超載)” 與 “擴展” 原來類別的行為時,才有必要設計 “特殊化類別”。

再來從 “汽車工廠” 的角度來觀察時,它提供了 “列出所有車況” 這個操作給外界來使用(有可能是部隊指揮官想知道部隊內所有各類型車子的車況),請注意,”汽車工廠” 是將所有車子的類型,包括卡車、坦克車、悍馬車…等,均當作 “一般性車子” 來看待,因為,這些特殊軍用車輛,仍是具備了 “車子” 的共同特性,所以並不需要讓外界個別來宣告與存取這些特殊化類別,只要透過 “車子” 的 “get車況” 操作,然後才在動態的期間,來呼叫這些實體(instance)物件的 “get車況” 操作。如此封裝了這些特殊化類別的變動設計(你不知道哪時候又會增加了 “奘甲飛彈車” 這種新的特殊化類別設計),卻又能動態存取這些特殊化類別的操作,這就是 “多型(polymorphism)” 的效果!


※延伸參考:
 o 「類別之間的關係(Relationship) — 結合(Association)關係 (2)」
  http://www.kenming.idv.tw/index.php?title=ei_a_yas_e_c_e_ai_relationship_a_a_ael_a_2&more=1&c=1&tb=1&pb=1
 o 「類別之間的關係(Relationship) — 結合(Association)關係 (1)」
  http://www.kenming.idv.tw/index.php?title=ei_a_yas_e_c_e_ai_relationship_a_cm_a_as_1&more=1&c=1&tb=1&pb=1
 o 「淺論「類別(Class)是什麼?」」
  http://www.kenming.idv.tw/index.php?title=amoel_a_ei_a_y_class_a_mar_eofif_a&more=1&c=1&tb=1&pb=1
 o 「淺論「什麼是物件(Object)?」」
  http://www.kenming.idv.tw/index.php?title=amoel_a_ar_eofa_mc_carp_object_if_a&more=1&c=1&tb=1&pb=1


Java 程式範例碼


#001 public class 車子 {
#002 public String get車況(){
#003 return "我是一般化車子...";
#004 }
#005 }

#001 public class 卡車 extends 車子 {
#002 public String get車況(){
#003 return "我是卡車,可以裝載很多物資...";
#004 }
#005 public String 裝載物資(String 物資){
#006 return "";
#007 }
#008 }

#001 public class 坦克車 extends 車子 {
#002 public String get車況(){
#003 return "我是坦克車,可以發射大砲...";
#004 }
#005
#006 public void 發射大砲(){
#007 }
#008 }

#001 public class 悍馬車 extends 車子 {
#002 public String get車況(){
#003 return "我是悍馬車,機動靈活也可以發射火箭炮...";
#004 }
#005 public void 發射火箭炮(){
#006 }
#007 }

#001 import java.util.*;
#002 public class 汽車工廠 {
#003 private ArrayList list = new ArrayList();
#004
#005 public 汽車工廠(){
#006 list.add(製造(0));
#007 list.add(製造(1));
#008 list.add(製造(2));
#009 list.add(製造(3));
#010 }
#011
#012 public String 列出所有車子(){
#013 String 車子資訊="";
#014 Iterator e = list.iterator();
#015 while (e.hasNext())
#016 車子資訊 = 車子資訊 + ((車子)e.next()).get車況() + "\n";
#017 return 車子資訊;
#018 }
#019
#020 private 車子 製造(int 型別){
#021 switch(型別){
#022 case 0: return new 車子();
#023 case 1: return new 卡車();
#024 case 2: return new 悍馬車();
#025 case 3: return new 坦克車();
#026 default: return new 車子();
#027 }
#028 }
#029 }



這裡設計一個測試用的 Java stand-alone 的程式: TestCar,以站在 “汽車工廠r” 的角度,來看看如何取得工廠內所有車子的車況:


#001 public class TestCar {
#002 public static void main(String[] args) {
#003 汽車工廠 factory = new 汽車工廠();
#004
#005 System.out.println(factory.列出所有車子());
#006 }
#007 }


執行結果如下:

我是一般化車子...
我是卡車,可以裝載很多物資...
我是悍馬車,機動靈活也可以發射火箭炮...
我是坦克車,可以發射大砲...


原始碼下載:
http://files.hsdc.idv.tw/src/car_sample-3.rar
== 簽名檔 ==
= 寸心千里=
= blog: http://www.kenming.idv.tw/
= 軟體課程訊息 http://www.hsdc.com.tw/
別忘捐VP感謝幫助你的人 新手會員瞧一瞧
目前尚無任何回覆
   

回覆
如要回應,請先登入.