UML類圖與程序設(shè)計(jì)

類的理解

類(Class)封裝了數(shù)據(jù)和行為,是面向?qū)ο蟮闹匾M成部分,它是具有相同屬性、操作、關(guān)系的對(duì)象集合的總稱。在系統(tǒng)中,每個(gè)類都具有一定的職責(zé),職責(zé)指的是類要完成什么樣的功能,要承擔(dān)什么樣的義務(wù)。一個(gè)類可以有多種職責(zé),設(shè)計(jì)得好的類一般只有一種職責(zé)。在定義類的時(shí)候,將類的職責(zé)分解成為類的屬性和操作(即方法)。類的屬性即類的數(shù)據(jù)職責(zé),類的操作即類的行為職責(zé)。設(shè)計(jì)類是面向?qū)ο笤O(shè)計(jì)中最重要的組成部分,也是最復(fù)雜和最耗時(shí)的部分。

在軟件系統(tǒng)運(yùn)行時(shí),類將被實(shí)例化成對(duì)象(Object),對(duì)象對(duì)應(yīng)于某個(gè)具體的事物,是類的實(shí)例(Instance)。

類圖(Class Diagram)使用出現(xiàn)在系統(tǒng)中的不同類來描述系統(tǒng)的靜態(tài)結(jié)構(gòu),它用來描述不同的類以及它們之間的關(guān)系。

在系統(tǒng)分析與設(shè)計(jì)階段,類通常可以分為三種,分別是實(shí)體類(Entity Class)、控制類(Control Class)和邊界類(Boundary Class),下面對(duì)這三種類加以簡(jiǎn)要說明:

(1) 實(shí)體類:實(shí)體類對(duì)應(yīng)系統(tǒng)需求中的每個(gè)實(shí)體,它們通常需要保存在永久存儲(chǔ)體中,一般使用數(shù)據(jù)庫(kù)表或文件來記錄,實(shí)體類既包括存儲(chǔ)和傳遞數(shù)據(jù)的類,還包括操作數(shù)據(jù)的類。實(shí)體類來源于需求說明中的名詞,如學(xué)生、商品等。

(2) 控制類:控制類用于體現(xiàn)應(yīng)用程序的執(zhí)行邏輯,提供相應(yīng)的業(yè)務(wù)操作,將控制類抽象出來可以降低界面和數(shù)據(jù)庫(kù)之間的耦合度。控制類一般是由動(dòng)賓結(jié)構(gòu)的短語(yǔ)(動(dòng)詞+名詞)轉(zhuǎn)化來的名詞,如增加商品對(duì)應(yīng)有一個(gè)商品增加類,注冊(cè)對(duì)應(yīng)有一個(gè)用戶注冊(cè)類等

(3) 邊界類:邊界類用于對(duì)外部用戶與系統(tǒng)之間的交互對(duì)象進(jìn)行抽象,主要包括界面類,如對(duì)話框、窗口、菜單等。

在面向?qū)ο蠓治龊驮O(shè)計(jì)的初級(jí)階段,通常首先識(shí)別出實(shí)體類,繪制初始類圖,此時(shí)的類圖也可稱為領(lǐng)域模型,包括實(shí)體類及其它們之間的相互關(guān)系。

類與類之間的關(guān)系

  1. 關(guān)聯(lián)關(guān)系

關(guān)聯(lián)(Association)關(guān)系是類與類之間最常用的一種關(guān)系,它是一種結(jié)構(gòu)化關(guān)系,用于表示一類對(duì)象與另一類對(duì)象之間有聯(lián)系,如汽車和輪胎、師傅和徒弟、班級(jí)和學(xué)生等等。在UML類圖中,用實(shí)線連接有關(guān)聯(lián)關(guān)系的對(duì)象所對(duì)應(yīng)的類,在使用Java、C#和C++等編程語(yǔ)言實(shí)現(xiàn)關(guān)聯(lián)關(guān)系時(shí),通常將一個(gè)類的對(duì)象作為另一個(gè)類的成員變量。在使用類圖表示關(guān)聯(lián)關(guān)系時(shí)可以在關(guān)聯(lián)線上標(biāo)注角色名,一般使用一個(gè)表示兩者之間關(guān)系的動(dòng)詞或者名詞表示角色名(有時(shí)該名詞為實(shí)例對(duì)象名),關(guān)系的兩端代表兩種不同的角色,因此在一個(gè)關(guān)聯(lián)關(guān)系中可以包含兩個(gè)角色名,角色名不是必須的,可以根據(jù)需要增加,其目的是使類之間的關(guān)系更加明確。

如在一個(gè)登錄界面類LoginForm中包含一個(gè)JButton類型的注冊(cè)按鈕loginButton,它們之間可以表示為關(guān)聯(lián)關(guān)系,代碼實(shí)現(xiàn)時(shí)可以在LoginForm中定義一個(gè)名為loginButton的屬性對(duì)象,其類型為JButton。如圖1所示:

img

圖1 關(guān)聯(lián)關(guān)系實(shí)例

圖1對(duì)應(yīng)的Java代碼片段如下:

public class LoginForm {
  private JButton loginButton; // 定義為成員變量 
  ... 
} 

public class JButton {
  ... 
}

在UML中,關(guān)聯(lián)關(guān)系通常又包含如下幾種形式:

(1) 雙向關(guān)聯(lián)

默認(rèn)情況下,關(guān)聯(lián)是雙向的。例如:顧客(Customer)購(gòu)買商品(Product)并擁有商品,反之,賣出的商品總有某個(gè)顧客與之相關(guān)聯(lián)。因此,Customer類和Product類之間具有雙向關(guān)聯(lián)關(guān)系,如圖2所示:

img

圖2 雙向關(guān)聯(lián)實(shí)例

圖2對(duì)應(yīng)的Java代碼片段如下:

public class Customer {
  private Product[] products; 
  ... 
}  

public class Product { 
  private Customer customer;
  ...
}

(2) 單向關(guān)聯(lián)

類的關(guān)聯(lián)關(guān)系也可以是單向的,單向關(guān)聯(lián)用帶箭頭的實(shí)線表示。例如:顧客(Customer)擁有地址(Address),則Customer類與Address類具有單向關(guān)聯(lián)關(guān)系,如圖3所示:

img

圖3 單向關(guān)聯(lián)實(shí)例

圖3對(duì)應(yīng)的Java代碼片段如下:

public class Customer {
  private Address address; 
  ... 
}  
public class Address {
  ... 
}

(3) 自關(guān)聯(lián)

在系統(tǒng)中可能會(huì)存在一些類的屬性對(duì)象類型為該類本身,這種特殊的關(guān)聯(lián)關(guān)系稱為自關(guān)聯(lián)。例如:一個(gè)節(jié)點(diǎn)類(Node)的成員又是節(jié)點(diǎn)Node類型的對(duì)象,如圖4所示:

img

圖4 自關(guān)聯(lián)實(shí)例

圖4對(duì)應(yīng)的Java代碼片段如下:

public class Node { 
  private Node subNode; 
  ... 
}

(4) 多重性關(guān)聯(lián)

多重性關(guān)聯(lián)關(guān)系又稱為重?cái)?shù)性(Multiplicity)關(guān)聯(lián)關(guān)系,表示兩個(gè)關(guān)聯(lián)對(duì)象在數(shù)量上的對(duì)應(yīng)關(guān)系。在UML中,對(duì)象之間的多重性可以直接在關(guān)聯(lián)直線上用一個(gè)數(shù)字或一個(gè)數(shù)字范圍表示。

對(duì)象之間可以存在多種多重性關(guān)聯(lián)關(guān)系,常見的多重性表示方式如表1所示:

表1 多重性表示方式列表

表示方式 多重性說明
1..1 表示另一個(gè)類的一個(gè)對(duì)象只與該類的一個(gè)對(duì)象有關(guān)系
0..* 表示另一個(gè)類的一個(gè)對(duì)象與該類的零個(gè)或多個(gè)對(duì)象有關(guān)系
1..* 表示另一個(gè)類的一個(gè)對(duì)象與該類的一個(gè)或多個(gè)對(duì)象有關(guān)系
0..1 表示另一個(gè)類的一個(gè)對(duì)象沒有或只與該類的一個(gè)對(duì)象有關(guān)系
m..n 表示另一個(gè)類的一個(gè)對(duì)象與該類最少m,最多n個(gè)對(duì)象有關(guān)系 (m≤n)

例如:一個(gè)界面(Form)可以擁有零個(gè)或多個(gè)按鈕(Button),但是一個(gè)按鈕只能屬于一個(gè)界面,因此,一個(gè)Form類的對(duì)象可以與零個(gè)或多個(gè)Button類的對(duì)象相關(guān)聯(lián),但一個(gè)Button類的對(duì)象只能與一個(gè)Form類的對(duì)象關(guān)聯(lián),如圖5所示:

img

圖5 多重性關(guān)聯(lián)實(shí)例

圖5對(duì)應(yīng)的Java代碼片段如下:

public class Form {
  private Button[] buttons; //定義一個(gè)集合對(duì)象 
  ... 
} 
public class Button {
  ... 
}

(5) 聚合關(guān)系

聚合(Aggregation)關(guān)系表示整體與部分的關(guān)系。在聚合關(guān)系中,成員對(duì)象是整體對(duì)象的一部分,但是成員對(duì)象可以脫離整體對(duì)象獨(dú)立存在。在UML中,聚合關(guān)系用帶空心菱形的直線表示。例如:汽車發(fā)動(dòng)機(jī)(Engine)是汽車(Car)的組成部分,但是汽車發(fā)動(dòng)機(jī)可以獨(dú)立存在,因此,汽車和發(fā)動(dòng)機(jī)是聚合關(guān)系,如圖6所示:

img

圖6 聚合關(guān)系實(shí)例

在代碼實(shí)現(xiàn)聚合關(guān)系時(shí),成員對(duì)象通常作為構(gòu)造方法、Setter方法或業(yè)務(wù)方法的參數(shù)注入到整體對(duì)象中,圖6對(duì)應(yīng)的Java代碼片段如下:

public class Car { 
  private Engine engine;
  //構(gòu)造注入 
  public Car(Engine engine) { 
    this.engine = engine;   
  }          
  //設(shè)值注入 
  public void setEngine(Engine engine) {
    this.engine = engine; 
  } 
  ... 
} 

public class Engine { 
  ... 
} 

(6) 組合關(guān)系

組合(Composition)關(guān)系也表示類之間整體和部分的關(guān)系,但是在組合關(guān)系中整體對(duì)象可以控制成員對(duì)象的生命周期,一旦整體對(duì)象不存在,成員對(duì)象也將不存在,成員對(duì)象與整體對(duì)象之間具有同生共死的關(guān)系。在UML中,組合關(guān)系用帶實(shí)心菱形的直線表示。例如:人的頭(Head)與嘴巴(Mouth),嘴巴是頭的組成部分之一,而且如果頭沒了,嘴巴也就沒了,因此頭和嘴巴是組合關(guān)系,如圖7所示:

img

圖7 組合關(guān)系實(shí)例

在代碼實(shí)現(xiàn)組合關(guān)系時(shí),通常在整體類的構(gòu)造方法中直接實(shí)例化成員類,圖7對(duì)應(yīng)的Java代碼片段如下:

public class Head { 
  private Mouth mouth;
  public Head() { 
    mouth = new Mouth(); //實(shí)例化成員類   
  } 
  ... 
}  

public class Mouth {
  ... 
} 

類與類之間的關(guān)系(2)

  1. 依賴關(guān)系

依賴(Dependency)關(guān)系是一種使用關(guān)系,特定事物的改變有可能會(huì)影響到使用該事物的其他事物,在需要表示一個(gè)事物使用另一個(gè)事物時(shí)使用依賴關(guān)系。大多數(shù)情況下,依賴關(guān)系體現(xiàn)在某個(gè)類的方法使用另一個(gè)類的對(duì)象作為參數(shù)。在UML中,依賴關(guān)系用帶箭頭的虛線表示,由依賴的一方指向被依賴的一方。例如:駕駛員開車,在Driver類的drive()方法中將Car類型的對(duì)象car作為一個(gè)參數(shù)傳遞,以便在drive()方法中能夠調(diào)用car的move()方法,且駕駛員的drive()方法依賴車的move()方法,因此類Driver依賴類Car,如圖1所示:

img

圖1 依賴關(guān)系實(shí)例

在系統(tǒng)實(shí)施階段,依賴關(guān)系通常通過三種方式來實(shí)現(xiàn),第一種也是最常用的一種方式是如圖1所示的將一個(gè)類的對(duì)象作為另一個(gè)類中方法的參數(shù),第二種方式是在一個(gè)類的方法中將另一個(gè)類的對(duì)象作為其局部變量,第三種方式是在一個(gè)類的方法中調(diào)用另一個(gè)類的靜態(tài)方法。圖1對(duì)應(yīng)的Java代碼片段如下:

public class Driver {   
  public void drive(Car car) { 
    car.move(); 
  }     
  ... 
}  

public class Car { 
  public void move() {
    ...
  }
  ... 
} 
  1. 泛化關(guān)系

泛化(Generalization)關(guān)系也就是繼承關(guān)系,用于描述父類與子類之間的關(guān)系,父類又稱作基類或超類,子類又稱作派生類。在UML中,泛化關(guān)系用帶空心三角形的直線來表示。在代碼實(shí)現(xiàn)時(shí),我們使用面向?qū)ο蟮睦^承機(jī)制來實(shí)現(xiàn)泛化關(guān)系,如在Java語(yǔ)言中使用extends關(guān)鍵字、在C++/C#中使用冒號(hào)“:”來實(shí)現(xiàn)。例如:Student類和Teacher類都是Person類的子類,Student類和Teacher類繼承了Person類的屬性和方法,Person類的屬性包含姓名(name)和年齡(age),每一個(gè)Student和Teacher也都具有這兩個(gè)屬性,另外Student類增加了屬性學(xué)號(hào)(studentNo),Teacher類增加了屬性教師編號(hào)(teacherNo),Person類的方法包括行走move()和說話say(),Student類和Teacher類繼承了這兩個(gè)方法,而且Student類還新增方法study(),Teacher類還新增方法teach()。如圖2所示:

img

圖2 泛化關(guān)系實(shí)例

圖2對(duì)應(yīng)的Java代碼片段如下:

//父類 
public class Person { 
  protected String name; 
  protected int age; 
  public void move() { 
    ... 
  }      
  public void say() {   
    ...     
  } 
}  

//子類 
public class Student extends Person { 
  private String studentNo;
  public void study() {  
    ...
  } 
}  

//子類 
public class Teacher extends Person { 
  private String teacherNo; 
  public void teach() {  
    ...
  } 
}
  1. 接口與實(shí)現(xiàn)關(guān)系

在很多面向?qū)ο笳Z(yǔ)言中都引入了接口的概念,如Java、C#等,在接口中,通常沒有屬性,而且所有的操作都是抽象的,只有操作的聲明,沒有操作的實(shí)現(xiàn)。UML中用與類的表示法類似的方式表示接口,如圖3所示:

img

圖3 接口的UML圖示

接口之間也可以有與類之間關(guān)系類似的繼承關(guān)系和依賴關(guān)系,但是接口和類之間還存在一種實(shí)現(xiàn)(Realization)關(guān)系,在這種關(guān)系中,類實(shí)現(xiàn)了接口,類中的操作實(shí)現(xiàn)了接口中所聲明的操作。在UML中,類與接口之間的實(shí)現(xiàn)關(guān)系用帶空心三角形的虛線來表示。例如:定義了一個(gè)交通工具接口Vehicle,包含一個(gè)抽象操作move(),在類Ship和類Car中都實(shí)現(xiàn)了該move()操作,不過具體的實(shí)現(xiàn)細(xì)節(jié)將會(huì)不一樣,如圖4所示:

img

圖4 實(shí)現(xiàn)關(guān)系實(shí)例

實(shí)現(xiàn)關(guān)系在編程實(shí)現(xiàn)時(shí),不同的面向?qū)ο笳Z(yǔ)言也提供了不同的語(yǔ)法,如在Java語(yǔ)言中使用implements關(guān)鍵字,而在C++/C#中使用冒號(hào)“:”來實(shí)現(xiàn)。圖4對(duì)應(yīng)的Java代碼片段如下:

public interface Vehicle { 
  public void move(); 
}  

public class Ship implements Vehicle { 
  public void move() {    
    ...    
  } 
}  

public class Car implements Vehicle { 
  public void move() {
    ...
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 在UML 2.0的13種圖形中,類圖是使用頻率最高的UML圖之一。Martin Fowler在其著作《UML Di...
    雷雷_zll閱讀 13,346評(píng)論 0 14
  • 忘記了uml類圖連線之間的關(guān)系,記錄一下。 1. 關(guān)聯(lián)關(guān)系 關(guān)聯(lián)(Association)關(guān)系是類與類之間最常用的...
    cutieagain閱讀 1,865評(píng)論 0 2
  • 在UML類圖中,常見的有以下幾種關(guān)系:泛化(Generalization),實(shí)現(xiàn)(Realization),關(guān)聯(lián)(...
    mocobk閱讀 1,167評(píng)論 0 1
  • 這里不會(huì)將UML的各種元素都提到,我只想講講類圖中各個(gè)類之間的關(guān)系; 能看懂類圖中各個(gè)類之間的線條、箭頭代表什么意...
    a2bfbb8a095f閱讀 1,849評(píng)論 0 1
  • 似乎下了快一個(gè)多月的雨了,喜歡效外活動(dòng)的我,感覺要發(fā)霉了,今天終于晴了,和朋友一家抓住機(jī)會(huì)去了東西湖區(qū)的“天鵝湖"...
    貓咪06閱讀 206評(píng)論 0 2