包是UML中管理元素的有效手段,UML中的所有元素均隸屬於某一個包,即使你沒有指定元素所屬的包,這些元素也會被置於一個默認包中,包的本質是命名空間。當我們在一個包中需要訪問另一個包中的元素時,可以使用符號“::”逐級引用。
例如在下圖所示的包圖中,存在兩支包含多個層次的包,如果包A3中的元素需要訪問包B3中的元素C,則可以使用B1::B2::B3::C的形式達到目的。
不同包中的元素進行交互是常態而不是偶發現象,使用符號“::”引用其他包中的元素,特別是在包的層級較深時,元素前面會有長長的由“::”連接的包路徑。對人類而言,這種冗長的形式無論是書寫還是閲讀都是一項具有挑戰性的工作,它影響的不只是效率,可讀性也大打折扣。為解決這個問題,UML提供了包導入的機制,例如在上面這種情況下,我們可以將包B3導入到包A3中,其圖形化表示如下圖所示。導入關係使用由導入包發出終止於被導入包的虛線箭頭表示,並需要標註“<
一旦包B3被導入包A3中,包B3就如同成了包A3的一個虛擬的子包,在遵循可見性規則的前提下,包A3中的元素就像使用子包中的元素一樣使用包B3中的元素。在下圖中,使用虛線在包A3中描畫包B3,表達了這種虛擬的關係。
注:關於UML中可見性的説明,可參見文章《修飾符》中“可見性修飾符”部分。
包的設計本質上應有其內在邏輯含義,但客觀上它也是解決命名衝突的一種手段,而通過import向一個包導入另一個包時,如果被導入的包中與當前包中存在同名元素就會產生名稱衝突。在這種情況下,被導入包中的衝突元素將被忽略而不被導入,如果需要使用這個產生衝突的元素,我們將不得不繼續使用“::”的形式來進行意圖表達。這就正如當前包中的元素與子包中的元素名稱產生衝突時一樣。
如上文所述,將一個包全部導入到另一個包中可能會產生諸如名稱衝突或其他潛在問題。如果一個包只使用另一個包中一個或少數幾個元素,更好的做法是僅導入那些我們需要的元素。例如包A3僅需要使用包B3中的元素C,則在導入時,可僅導入元素C,在圖形描畫上,導入箭頭直接指向元素C即可,如下圖所示。
僅導入需要的元素時,將只有被導入的元素可直接使用,而那些與被導入元素位於同一包的其他元素對當前包則需要繼續使用符號“::”引用。在上述示例中,被導入的元素C在使用邏輯上也如同直接在包A3中定義一樣,而元素D則是包A3之外位於其他包中的一個普通元素。
僅導入特定元素降低了導入產生潛在問題的可能性,但是也有可能被導入的元素與當前包中的元素碰巧產生了衝突。例如我們要在包A3中導入包B3中的元素C,但包A3中已經包含了一個名為C的元素,導入產生名稱衝突。此時,我們可以使用“<
上述對import的説明重點在import使用和細節上,但其實<
在下圖中,同時描畫了包之間的import和access關係,包B訪問包A1而導入包A2。
在UML的場景下,包B中的元素使用包A1和A2並無二致,我們可將包A1與A2均視為包B中虛擬的子包,但這兩種依賴關係的效果有一個明顯的區別,即“<
在編程時包之間的依賴關係如果設置有誤,往往會在程序編譯與運行時發生異常,UML僅通過圖形表達相關關係,不同UML工具對依賴的檢查並不一致,所以需要仔細檢查確認。
參考文獻:
1.《OCUP 2 Certification Guide_ Preparing for the OMG Certified UML 2.5 Professional 2 Foundation Exam》 Michael Jesse Chonoles
2.《OMG® Unified Modeling Language® (OMG UML®) Version 2.5.1》