- UML2面向對象分析與設計(第2版)
- 譚火彬編著
- 3934字
- 2019-07-01 10:17:33
1.4 面向對象技術的相關原則
在介紹完對象和類的基本概念后,本節將介紹面向對象技術的幾個重要的相關原則。對象和類作為面向對象技術的核心,存在著很多與之相關的原則,這些原則決定了面向對象技術的本質特征,只有遵循了這些原則,才是一個符合面向對象技術的方案。
1.4.1 抽象
世界是復雜的,為了處理這種復雜性,需要將其中的內容抽象化。抽象(Abstraction)的過程就是揭示事物區別于其他事物的本質特征的過程,是一個分析和理解問題的過程,這個過程取決于使用者的目的,它應該包括使用者所感興趣的那些職責問題,而忽略掉其他不相關的部分。從對象到類的過程就是抽象的過程,即將所見到的具體實體抽象成概念,從而可以在計算機世界中進行描述和對其采取各種操作。
抽象過程并沒有唯一的答案,同一個實體在不同的業務場景中可能有不同的抽象。同樣是一批人,根據使用選課系統的目的不同,可以將其中的一部分人抽象為老師,而將另一部分人抽象為學生,這個過程與具體應用場景密切相關。這也是面向對象系統中最難應用的一個關鍵技術。
關于抽象的概念,這里可以舉一個簡單的例子。例如,針對“我想買一斤水果”這件事,根據不同人的喜好,會產生不同的實例(有人可能買了一斤香蕉,有人可能買了一斤蘋果,或買了一斤橘子,這都是滿足要求的)。在這里,“水果”就是一個抽象,通過這個抽象概念,可以代表很多種不同的情況,從而適應不同人的胃口,而實際上并不存在水果這個實體(即對象)。面向對象的系統也是這樣的,通過抽象技術,可以使軟件能夠快速適應不斷變更的需求。
1.4.2 封裝
封裝(Encapsulation)是指對象對其訪問者隱藏具體的實現,它是軟件模塊化思想的體現。
通過封裝實現信息隱藏和數據抽象。信息隱藏的出發點是對象的私有數據不能被外界存取,從而保證外界以合法的手段(對象所提供的操作)訪問。同時,將數據抽象為一組行為,而不是內部的具體數據結構,把用戶隔離在實現細節之外,從而使得軟件各個部分依賴于抽象層,各模塊獲得自由。
通過封裝還可以保證數據的一致性。使用傳統的結構化方法,是很難保證這一點的。例如,郵政地址由地址和郵政編碼兩部分組成,而這兩部分信息應該是一致的,北京市市區的郵政編碼應該為100×××,上海市市區的郵政編碼應該為200×××,如果一個北京的地址對應的郵政編碼為200001,這肯定是不正確的,會造成系統異常。因此,為避免這種情況出現,所有操作這個數據結構的程序員必須嚴格遵守一系列業務邏輯規則;否則,很容易破壞數據的一致性。而這在處理大型項目、多人協同開發項目時,是很難保證的。面向對象的封裝就能夠保證這一點,外部用戶并不直接操作這些屬性,而是通過特定的操作來完成指定的運算,外界只知道操作的接口,而不關注具體的業務邏輯規則,從根本上杜絕了數據的不一致問題(見下面的代碼)。
class ShippingAddress{ private long cityCode; private string address; public longModifyAddress(String address) }
1.4.3 分解
分解(Decomposition)是指將單個大規模復雜系統劃分為多個不同的小構件。分解后的構件通過抽象和封裝等技術形成相對獨立的單元,這些單元可以獨立地設計和開發,從而實現化繁為簡、分而治之,以應對系統的復雜性,降低軟件開發成本。
在傳統的結構化方法中,開發人員可以通過函數、模塊等進行功能分解,實現模塊化設計,可以通過耦合和內聚來判斷分解的合理性,將系統分解為多個高內聚、低耦合的模塊。而面向對象的分解則更為復雜,在基于類和對象分解的基礎上,還需要進一步考慮類之間依賴程度、復用問題和穩定性問題等,進行合理的打包和分層,從而形成更加復雜的分解結構。
抽象、封裝和分解是系統設計中3個最基本的原則,它們相輔相成。一個對象圍繞著單一的抽象概念建立了一個封裝體,而系統則可以被分解為多個對象,并對這些對象進行進一步打包,從而形成更高層的抽象概念。
1.4.4 泛化
泛化(Generalization)是類與類之間一種非常重要的關系,通過這種關系,一個類可以共享另外一個或多個類的結構和行為。為了實現泛化關系,我們引入了繼承(Inheritance)機制。一個子類(Subclass)繼承一個或多個父類(Superclass),從而實現了不同的抽象層次。這些層次之間所建立的is a或is kind of關系,即為泛化關系。通過這種關系可以很容易地復用已經存在的數據和代碼,并實現多態處理。根據父類的個數不同,存在著單一繼承和多重繼承兩種情況。
單一繼承(Single Inheritance)是指一個類繼承另外一個類,圖1-6展示了兩個單一繼承的實例,類Saving和類Account、類Checking和類Account通過單一繼承構成兩個泛化關系,表明一個存儲賬戶(Saving)是一種賬戶(Account),一個支出賬戶(Checking)也是一種賬戶;它們都包含賬戶的信息(賬號no、用戶名name、余額balance),也都可以進行取款(Withdraw)操作。

圖1-6 單一繼承
多重繼承(Multiple Inheritance)是指一個類繼承另外多個類的屬性和行為。如圖1-7所示,類Bird同時繼承類FlyingThing和類Animal,這是一個多重繼承,表明鳥(Bird)即是一種飛行物(FlyingThing),又是一種動物(Animal)。

圖1-7 多重繼承
在實際系統應用中,對多重繼承的使用一定要謹慎。因為有些編程語言(如Java)不支持多重繼承,這會造成設計方案無法被實現。此外,即使像C++這樣支持多重繼承的語言,在實際應用過程中也會存在諸如名稱沖突、二義性等問題。
泛化關系提供了有效的復用手段,那么在實際應用中,一個子類到底繼承了父類的什么元素呢?繼承后的子類又可以進行什么樣的操作呢?
可以這樣認為,一個子類會繼承父類所有的元素(可能有些元素對于子類不可見),這包括屬性、操作和關系。此外,子類還可以根據自己的需要添加額外的屬性、操作或關系,還可對父類已有的操作進行重新定義。
圖1-8展示了一種繼承層次關系,其中子類(GraduateStudent)從父類(Student)繼承,它繼承了父類全部屬性和操作,所以即使GraduateStudent中沒有定義getName(),其也會從Student中得到getName()方法的全部實現。此外,子類也會繼承父類中的關系,因此GraduateStudent與Account也有聚合關系。

圖1-8 繼承層次關系
1.4.5 多態
多態(Polymorphism)是在同一外表(接口)下表現出多種行為的能力,它是對象技術的根本特征,是將對象技術稱為面向對象的原因所在。對象技術正是利用多態提供的動態行為特征,來封裝變化、適應變更,以達到系統的穩定目標。
圖1-9展示了一個多態的應用案例。面向對象的多態必須要有泛化關系的支持(有的文獻會把模板這種機制也稱為多態,這種參數化多態不需要泛化關系支持),如Rectangle(矩形)和Circle(圓形)均繼承自Shape(Shape以斜體字表示,表明該類是一個抽象類)。通過Shape提供的接口draw()實現畫圖功能的多態性,即根據目標的不同畫出不同的形狀。

圖1-9 通過泛化支持多態
現在假設有一個數組sharr,其中放著一排形狀Shape,但不知道哪些是矩形,哪些是圓形。利用多態性,完全可以不關注這些細節,而直接畫出目標形狀(見下面代碼)。
for(int i=0; i sharr.length; ++i){ Shape shape=(Shape)sharr[i]; shape.draw(); }
在遍歷整個數組的過程中,各個Shape知道應當如何在畫布上繪制自己的形狀。shape.draw()這行代碼在Shape指向不同的對象時將表現出不同的行為,這就是所謂多態。
1.4.6 分層
通過分解和抽象可以很容易對系統進行劃分。然而即使是簡單的應用,也可能很難一次性地完成系統的分解——無法想象一次性地將系統分解為幾十個,甚至上百個類。人們往往首先將系統分解成幾個獨立的部分(如先劃分為若干層或若干模塊),然后在此基礎上對每個部分再進一步分解小的部分,這些小的部分有的還可以進一步分解,直至形成最小的獨立單元(如類或函數)。這種逐級分解的思想就是分層。
分層(Hierarchy)是指面向不同的目標建立不同的抽象級別層次,從而在不同的抽象層次對系統進行分解,進一步簡化對系統的理解。在面向對象系統中,主要有兩種層次結構:類層次結構和對象層次結構。
類層次結構是指在不同的抽象級別進行對象的抽象,高層的類抽象層次更高,其描述能力也越強,而越往下抽象層次越低,底層的類則最具體,代表具體的事物。這些類之間通過泛化關系形成一種層次結構,也稱為繼承層次結構。此外,在這種層次結構中,一般同一層次的抽象級別是一樣的。圖1-10展示了一個繼承層次結構的實例,最高層的父類(Food)抽象層次最高,代表所有類型的食物(Food);第二層的類(Fruit、Vegetable和Meat)則相對要具體一些,代表某一類食物,如水果(Fruit);而最低層的類抽象層次最低,為具體類,可以實例化對象,本圖中代表具體的食物類型,如蘋果(Apple)、橙子(Orange)等。前兩層的類都是抽象類,不能構造具體的對象(UML類圖中用斜體字表示)。

圖1-10 類的繼承層次結構
類的繼承層次結構是面向對象系統中最普遍的結構,通過這種層次結構,可以分門別類地描述各類事物。很多設計良好的面向對象系統都是基于這種層次結構而構造的。
對象層次結構是指對象間的組成結構,即大的對象由小的對象組成(即分解成小的對象)。這種結構是通過類之間的聚合關系來實現的,也稱為聚合層次結構。這一種整體和部分的關系是逐層分解思想的具體體現。圖1-11給出了一個對象的聚合層次結構的實例,大學(University)由學院(School)和管理部門(Administration)組成,而學院又包含多個系(Department),每個系又由班級(Class)組成;管理部門則包括多個辦公室(Office)。

圖1-11 對象的聚合層次結構
1.4.7 復用
復用(Reuse)是借助于已有軟件的各種有關知識建立新的軟件的過程,以縮減新軟件開發和維護的成本。將軟件看成是由不同功能部分的構件所組成的有機體,每個構件在設計編寫時可以被設計成完成同類工作的通用工具,如果完成各種工作的構件被建立起來以后,編寫特定軟件的工作就變成了將各種不同構件進行組合的簡單問題,從而對軟件產品的最終質量和維護工作都有本質性的改變。第1.2.2小節把“復用”視為面向對象所帶來的優勢之一,而事實上要獲得這種優勢,在設計時就需要遵循復用的原則,設計可復用的構件。
在系統開發的各個階段都可能涉及復用,如從最低層的代碼復用到設計復用、架構復用,再到需求復用,甚至于延伸到特定業務領域的復用。復用原則要求設計者不僅針對當前的業務需求開展設計,還需要考慮業務的通用性和可擴展性等問題,從而設計抽象層次高、復用粒度大的組件。本書將在第6~7章中介紹一些具體用于可復用設計的原則和模式。
- Visual Basic 6.0程序設計計算機組裝與維修
- Practical Internet of Things Security
- 單片機C語言程序設計實訓100例:基于STC8051+Proteus仿真與實戰
- Android Application Development Cookbook(Second Edition)
- Mastering matplotlib
- 人人都是網站分析師:從分析師的視角理解網站和解讀數據
- Java應用開發技術實例教程
- C語言程序設計學習指導與習題解答
- ArcGIS By Example
- Highcharts Cookbook
- uni-app跨平臺開發與應用從入門到實踐
- Arduino機器人系統設計及開發
- Python編程基礎教程
- Neo4j 3.x入門經典
- Spring Web Services 2 Cookbook