6.1 包圖的概念
包是一種常規用途的組合機制。UML中的一個包直接對應於Java中的一個包,C#中的命名空間。在Java中,一個包可能含有其他包、類或者同時含有這兩者。進行建模時,通常使用邏輯性的包,用於對模型進行組織;使用物理性的包,用於轉換成系統中的Java包。
C#命名空間與java包的區別分析
本文實例分析了C#命名空間與java包的區別。分享給大家供大家參考。具體分析如下:
相同點:
1、都是為了重用性(reusebility)——軟件工程中一個非常重要的目標。 2、C#里面的命名空間和java中的包都屬於訪問權限的控制機制。 不同點: 1、C#命名空間只是一種邏輯上的結構,它允許所組織的類文件的物理存放位置與邏輯結構不一致,而Java中類文件的物理結構必須與邏輯結構一致。 2、Java的package本身沒有子包的概念,所有package都是並列的關系,沒有誰包含誰的問題。比如:org.dominoo.action和org.dominoo.action.asl之間絕對沒有包與子包的關系。它們是各自獨立的包,各自擁有自己的class/interface的集合。在org.dominoo.action.asl的某個java文件里,如果想引用org.dominoo.action里的某個class/interface,則必須import org.dominoo.action。 C++/C#的namespace方案則不然,一個namespace可以有自己的sub-namespace,我們不妨將namespace也稱為package,那么C++/C#的package之間就可能存在包與子包的關系. 3、Java中使用import語句而C#中使用using namespace語句。
6.1.1 包圖
包圖是描述包及其關系的圖。與所有UML的其它圖一樣,包圖可以包括注釋、約束。包間的關系有依賴關系和泛化關系。上圖是一個典型的包圖。
6.1.2 包的作用
在面向對象軟件開發的過程中,類顯然是構建整個系統的基本元素。但是對於大型的軟件系統而言,其包含的類將是成百上千,再加上類間的關聯關系、多重性等,必然是大大超出了人們對系統的理解和處理能力。為了便於管理這些類,我們引入了“包”這種分組元素。
包的作用是:
1.對語義上相關的元素進行分組。如,把功能相關的用例放在一個包中。
2.提供配置管理單元。如,以包為單位,對軟件進行安裝和配置。
3.在設計時,提供並行工作的單元。如,在設計階段,多個設計小組,可以同時對幾個相互獨立包中的類進行詳細設計。
4.提供封裝的命名空間,同一個包中,其元素的名稱必須惟一。
6.1.3 包中的元素
在包中可以擁有各種其它元素,包括類、接口、構件、節點、協作、用例,甚至是其它子包或圖 。一個元素只能屬於一個包。
命名方式
每個包必須有一個與其他包相區別的名稱,包的名字是一個字符串:
-
簡單名:僅含一個簡單的名稱。
-
路徑名::以包所位於的外圍包的名字作為前綴的包名
-
-
當不需要顯示包的內容時,將包的名字放入主方框內;
-
需要顯示內容時包的名字放入左上角的小方框中,將內容放入主方框內。
-
標以 {global} 的包叫通用包,表示系統的所有其他包都依賴於該包。
-
UML中,用文件夾符號來表示一個包。包由一個矩形表示,它包含2欄。下面是最常見的幾種包的表示法
6.2.1 包的名稱
每個包必須有一個與其他包相區別的名稱。標識包名稱的格式有兩種:簡單名和全名。
其中,簡單名僅包含包一個簡單的名稱;全名是用該包的外圍包的名字作為前綴,加上包本身的名字。
例如,Rose常用表示方法中,其包名UI就是一個簡單名。而包System.Web.UI才是一個完整帶路徑的名稱,表示UI這個包是位於System.Web命名空間中的。如圖所示
6.2.2 包的元素
在一個包中可以擁有各種其他元素,包括類、接口、構件、節點、協作、用例,甚至是其他包或圖。這是一種組成關系,意味着元素是在這個包中聲明的,因此一個元素只能屬於一個包。
每一個包就意味着一個獨立的命名空間,因此,兩個不同的包,可以具有相同的元素名,但由於所位於的包名不同,因此其全名仍然是不同的。
在包中表擁有的元素時,有兩種方法:一種是在第二欄中列出所屬元素名,一種是在第二欄中畫出所屬元素的圖形表示(參見下圖)。
6.2.3 包元素的可見性
像類中的屬性和方法一樣,包中的元素也有可見性,包內元素的可見性控制了包外部元素訪問包內部元素的權限。
包的可見性有3種:可以用“+”來表示“public”,即,該元素是共有的;用“#”來表示“protected”, 即該元素是保護的,用“-”來表示“private”, 即,該元素是私有的。
包內元素的可見性,標識了外部元素訪問包內元素的權限。表6-1列出了可見性與訪問權限的關系。
表6-1 可見性與訪問權限(假設包B中的元素訪問包A中的元素)
6.2.4 包的構造型
為了表示包的新特性,用構造型來描述包的新特征。包的構造型有5種,下面分別說明。
1.《system》構造型:《system》構造型的包表示整個系統.
2.《subsystem》構造型:《subsystem》構造型的包則表示正在建模的系統中某個獨立的子系統.
3.《facade》構造型:只是某個其它包的視圖,它主要用來為其它一些復雜的包提供簡略視圖
4.《stub》構造型:是一個代理包,它服務於某個其他包的公共內容,這通常應用於分布式系統的建模中 .
5.《framework》構造型:用來表示一個框架的,框架是一個領域內的應用系統提供可擴充模板的體系結構模式
6.3 包圖中的關系
包圖中的關系有2種:依賴關系、泛化關系。
6.3.1 依賴關系
1.《use》關系
《use》關系是一種默認的依賴關系 ,說明客戶包(箭尾端的包)中的元素以某種方式使用提供者包(箭頭端的包)的公共元素,也就是說客戶包依賴於提供者包。如果沒有指明依賴類型,則默認為《USE》關系。
例如在圖中,有兩個《USE》依賴,Client包將通過Server包來完成Order的存儲,而Server包使用System.Data.SqlClient包來實現數據庫的存儲。
2.《import》關系
《import》關系:最普遍的包依賴類型,說明提供者包的命名空間將被添加到客戶包的命名空間中,客戶包中的元素也能夠訪問提供者包的所有公共元素。
《import》關系使命名空間合並,當提供者包中的元素具有與客戶包中的元素相同的名稱時,將會導致命名空間的沖突。這也意味着,當客戶包的元素引用提供者包的元素時,將無需使用全稱,只需使用元素名稱即可。
例如在上圖中,Client包引用了(import)了Rule包,Rule包又引用了GUI包。同時,這還表示Client包間接引用了GUI包。
3.《access》關系
如果只想使用提供者包中的元素,而不想將兩個包合並,則應使用該關系。在客戶包中必須使用路徑名,才能訪問提供者包中的所有公共元素。
4.《trace》關系
想表示一個包到另一個包的歷史發展,則需要使用《trace》關系來表示
6.3.2 泛化關系
包間的泛化關系類似於類間的泛化關系,使用一般包的地方,可以用特殊包代替。
在系統設計中,對某一個特定的功能,有多種實現方法。例如,實現多數據庫支持;實現B/S和C/S雙界面。這時就需要定義一些高層次的“抽象包”和實現高層次功能的“實現包”。
在抽象包中定義一些接口和抽象類,在實現包中,定義一些包含實現這些抽象類和接口的具體類。例如在上圖中,說明GUI有兩種風格:一種是基於WinForm的C/S風格,一種是WebForm的B/S風格。
需要注意的是,在《在UML用戶手冊》中將其歸為泛化關系,而在《UML精粹》中卻將其看作是實現關系。
6.4 閱讀包圖
閱讀包圖的方法:
1.了解每個包的語義,它包含的元素語義。
2.理解包間的關系。
3.找到依賴關系復雜的包,從最復雜的包開始閱讀,然后以此是簡單的包。
例如,閱讀下面的包圖。
對上面包的理解如下:
(1)根據《use》關系可以發現Client包使用Server包,Server包使用System.Data.SqlClient包,根據它們所包含的元素語義,可以得知Client包負責Order(訂單)的輸入,並通過Server包來管理用戶的登錄(LoggingService)和數據庫存儲(DataBase);而Server包還通過.Net的SQL SERVER訪問工具包,來實現與數據庫的連接和通訊。
(2)看《import》關系,從RULE包所包含的元素語義可知,該包負責處理一些規則,並引用一個具體的窗體(Window);而Client包通過引用RULE來實現整個窗體和表單的顯示,輸入等,並且還將暫存Order(訂單)信息。
(3)接着來看包的泛化關系。GUI有兩個具體實現:一個是針對C/S的WindowsGUI,一個是實現B/S的WebGUI.
6.5 創建包圖
繪制包圖的基本過程主要有三個步驟:第一,尋找包;第二,確定包之間的關系;第三,標出包內元素的可見性。
繪制包圖的“最小化系統間的耦合關系”的原則:
最大限度減少包之間的依賴,包封裝時,避免包之間的循環依賴;最小化每個包的public、protected元素的個數,最大化每個包中private元素的個數。
6.5.1 尋找包
通過把具有很強語義聯系的建模元素分組,找出分析包。分析包必須反映元素的真實的語義分組,而不僅是邏輯架構的理想視圖。
我們以對象模型和用例模型為依據,把關系緊密的類分到同一個包中,把關系松散的類分到不同的包中。
1.標識候選包的原則:
(1).把類圖中關系緊密的類放到一個包中;
(2).在類繼承類層次中,把不同層次的類放在不同的包中。
也可以把用例模型作為包的來源。然而,用例橫跨分析包是非常普遍的——一個用例可以由幾個不同包中的類實現。
2.調整候選包
在已經識別一組候選包后,然后減少包間依賴,最小化每個包的public、protected元素的個數,最大化每個包中private元素的個數。做法是:
(1).在包間移動類;
(2).添加包或刪除包。
良好包結構的關鍵是包內高內聚,包間低耦合。
通常,當創建分析包模型時,應該盡量使包模型簡單。獲得正確的包集合比使用諸如包泛化和依賴構造型的特征更加重要,這些特征可以以后再添加,僅當使用諸如包泛化和依賴構造型的特征使得模型更加容易理解時,才使用這些包整理技術。除了保持簡單,還應該避免嵌套包。物件在嵌套包結構中埋藏得越深,模型變得越晦澀。
作為經驗法則,希望每個包具有4~10個分析類。然而,對於所有的經驗法則,卻存在例外,如果打破某個法則使得模型更加清晰,就采用這個法則!有時,你必須引入只帶有一個或者兩個類的包,因為你需要斷開包模型中的循環依賴。在這種情況下,這是完全合理的。
6.5.2 消除循環包依賴
應該盡量避免包模型中的循環依賴。如果包A以某種方式依賴包B,並且包B以某種方式依賴包A,就應該合並這兩個包,這是消除循環依賴非常有效的方法。但是經常起作用的、更好的方法是,努力分解公共元素成為第三個包C。重新計算依賴關系,以消除循環依賴。示例顯示在圖中。
很多建模工具允許自動驗證包間依賴。如果一個包中的元素訪問另一個包中的元素,但兩個包間卻沒有依賴關系,那么工具產生訪問沖突列表。
在分析模型中,不可能創建沒有訪問沖突的包圖。
6.6 包圖建模
包圖主要用於兩種不同層次的用途:一是對成組元素建模;二是對體系結構建模。
6.6.1 對成組元素建模
對成組元素進行建模可以說是包圖最常見的用途,它將建模元素組織成組,然后對組進行命名,在對成組元素建模時,應遵循以下幾個策略:
每個包都應該是由在概念上,語義上相互接近的元素組成。
對於每個包,找出應標記為公共的元素,但應盡可能地少。
一般使用默認的《use》構造型,在實現類時,才用《import》構造型代替《use》構造型。
采用泛化來對特殊包進行建模。
在構建包模型時,注意,在包中只標明對每個包起核心作用的元素;另外業可以標識每個包的文檔標記值,以使其更加清晰。
6.6.2 對體系結構建模
體系結構是一個軟件系統的核心邏輯結構,常用的體系結構模式包括分層、MVC、管道、黑板、微內核等,而在應用軟件中,分層和MVC是最常見的兩種結構。
在分層的體系結構中,最常見的划分是表示層(present)、邏輯層(business或domain)、數據層(包括數據訪問、日記等)。如果采用分層體系結構,我們就把每一層用一個包來表示,如圖所示
圖 用包分層