UML類圖詳解

zhengyi發表於2019-07-19

我們在閱讀開源專案時,總是希望能比較高效的整理清楚專案中的各個類之間的關係,那麼有沒有相應的工具能高效、簡潔的表示清楚類關係呢?UML類圖就是一個可以幫我們解決此類問題的工具或者方法。

1 什麼是UML

統一建模語言(Unified Modeling Language,縮寫UML)是非專利的第三代建模和規約語言。
UML是一種開放的方法,用於說明、視覺化、構建和編寫一個正在開發的、物件導向的、軟體密集系統的製品的開放方法。

UML模型和圖形

UML分為模型和圖形兩大類。區分UML模型和UML圖是非常重要的,UML圖(包括用例圖、協作圖、活動圖、序列圖、部署圖、構件圖、類圖、狀態圖)是模型中資訊的圖表表達形式,但是UML模型獨立於UML圖存在。

在UML系統開發中有三個主要的模型:

  • 功能模型:從使用者的角度展示系統的功能,包括用例圖。
  • 物件模型:採用物件,屬性,操作,關聯等概念展示系統的結構和基礎,包括類別圖、物件圖。
  • 動態模型:展現系統的內部行為。包括序列圖,活動圖,狀態圖。

UML2.2中一共定義了14種圖示。

結構性圖形(Structure diagrams)強調的是系統式的建模:

  • 靜態圖(static diagram):包括類圖、物件圖、包圖
  • 實現圖(implementation diagram):包括元件圖、部署圖
  • 剖面圖
  • 複合結構圖

行為式圖形(Behavior diagrams)強調系統模型中觸發的事件

  • 活動圖
  • 狀態圖
  • 用例圖

互動性圖形(Interaction diagrams),屬於行為圖形的子集合,強調系統模型中的資料流程

  • 通訊圖
  • 互動概述圖
  • 時序圖
  • 時間圖

2 UML類圖作用

UML展現了一系列最佳工程實踐,這些最佳實踐在對大規模,複雜系統進行建模方面,特別是軟體架構層次方面已經被驗證有效。

我們這次介紹的主要是類圖,為了解析專案的系統結構和架構層次,可以簡潔明瞭的幫助我們理解專案中類之間的關係。

類圖的作用:
(1):在軟體工程中,類圖是一種靜態的結構圖,描述了系統的類的集合,類的屬性和類之間的關係,可以簡化了人們對系統的理解;
(2):類圖是系統分析和設計階段的重要產物,是系統編碼和測試的重要模型。

3 類圖格式

在UML類圖中,類使用包含類名、屬性(field) 和方法(method) 且帶有分割線的矩形來表示,

舉個例子。一個Animal類,它包含name,age,state,isPet這4個屬性,以及name相關方法。

class Animal: NSObject {

	public var name: String?
	internal var isPet: Bool?
	fileprivate var state: String?
	private var age: Int? = 0

	override init() {
    	self.name = "no name"
    	self.age = 0
    	self.isPet = true
    	self.state = "dead"
	}

	public func getName() -> String {
    	return self.name!
	}

	internal func setName(name: String?) {
    	self.name = name
	}
}
複製程式碼

對應UML類圖:

AnimalUML類圖.png

  • 類名:粗體,如果是類是抽象類則類名顯示為斜體!
  • 屬性:

可見性 名稱:型別[=預設值]

可見性一般為public、private和protected,在類圖分別用+、-和#表示,在Swift中沒有與protected完全對應的可見控制,因此選用的是internal對應為#;名稱為屬性的名稱;型別為資料型別;預設值如變數 age預設值為0。

  • 方法:

可見性 名稱(引數列表 引數1,引數2) :返回型別

可見性如上名稱表示式的介紹,名稱就是方法名,引數列表是可選的項,多引數的話引數直接用英文逗號隔開;返回值也是個可選項,返回值型別可以說基本的資料型別、使用者自定義型別和void。如果是構造方法,則無返回型別!

4類與類之間的關係表達

類圖中類與類之間的關係主要由:繼承、實現、依賴、關聯、聚合、組合這六大型別。表示方式如下圖:

UML類與類之間關係.png

(1)繼承關係(Generalization/extends)

繼承關係也叫泛化關係,指的是一個類(稱為子類、子介面)繼承另外的一個類(稱為父類、父介面)的功能,並可以增加它自己的新功能的能力,繼承是類與類或者介面與介面之間最常見的關係。

繼承用實線空心箭頭表示,由子類指向父類。

下面寫兩個子類,Fish和Cat分別繼承自Animal。

class Fish: Animal {
    
    public var fishType: String?
    func swim() {
    }
}

class Cat: Animal {
    public var hasFeet: Bool?
    func playToy(doll:Doll) {
        doll.toyMoved()
    }
}
複製程式碼

Generalization.png

(2)實現關係(implements)

指的是一個class類實現interface介面(可以是多個)的功能;實現是類與介面之間最常見的關係;在Java中此類關係通過關鍵字implements明確標識,在iOS中我將其理解成代理的實現。

寫一個洋娃娃類Doll,該類遵循了ToyAction協議,實現了玩具移動的方法。

protocol ToyAction {
    func toyMoved() -> Void
}

class Doll: NSObject,ToyAction {
    
    public var body: Body?
    public var cloth: Cloth?
    
    func toyMoved() {
        //洋娃娃玩具動作具體實現
    }
}
複製程式碼

implements

(3)依賴關係(Dependency)

可以簡單的理解,就是一個類A使用到了另一個類B,而這種使用關係是具有偶然性的、、臨時性的、非常弱的,但是B類的變化會影響到A;比如某人要過河,需要借用一條船,此時人與船之間的關係就是依賴;表現在程式碼層面,為類B作為引數被類A在某個method方法中使用。

在我們的上述程式碼中Cat的playToy方法中引數引用了Doll,因此他們是依賴關係。

Dependency

(4)關聯關係(Association)

他體現的是兩個類、或者類與介面之間語義級別的一種強依賴關係,比如我和我的朋友;這種關係比依賴更強、不存在依賴關係的偶然性、關係也不是臨時性的,一般是長期性的,而且雙方的關係一般是平等的、關聯可以是單向、雙向的;表現在程式碼層面,為被關聯類B以類屬性的形式出現在關聯類A中,也可能是關聯類A引用了一個型別為被關聯類B的全域性變數;

寫一個Person類,他擁有一個寵物貓,他們之間的關係是關聯。

class Head: NSObject {
    
}

class Person: NSObject {
    public var pet: Cat?
    public var head: Head?
}
複製程式碼

association.png
](association.png)

(5)聚合關係(Aggregation)

聚合是關聯關係的一種特例,他體現的是整體與部分、擁有的關係,即has-a的關係,此時整體與部分之間是可分離的,他們可以具有各自的生命週期,部分可以屬於多個整體物件,也可以為多個整體物件共享;比如計算機與CPU、公司與員工的關係等;表現在程式碼層面,和關聯關係是一致的,只能從語義級別來區分;

class Cloth: NSObject {
    
}

class Body: NSObject {
    
}
複製程式碼

在上述程式碼中Doll由Body和Cloth組成,且即使失去Cloth,Doll也可以正常存在。

aggregation.png

(6)組合關係(Composition)

組合也是關聯關係的一種特例,他體現的是一種contains-a的關係,這種關係比聚合更強,也稱為強聚合;他同樣體現整體與部分間的關係,但此時整體與部分是不可分的,整體的生命週期結束也就意味著部分的生命週期結束;比如你和你的大腦;表現在程式碼層面,和關聯關係是一致的,只能從語義級別來區分;

上述程式碼中的Person擁有Head,並且這個整體和部分是不可分割的。

composition.png

最後來看看這個例子中的整體關係:

UML類圖示例.png

其實理解了之後我們發現還是很簡單的,學會了之後就可以投入實踐中了,舉一個簡單第三方庫的類圖例子,下圖是Masonry的類圖整理,可以看到專案結構很清晰的展示了出來。

Masonry類圖.png

​ ​
​ ​

相關文章