軟件工程與開發(fā)技術(shù)(西電第二版)第7章面向?qū)ο蠹夹g(shù)總論
《軟件工程與開發(fā)技術(shù)(西電第二版)第7章面向?qū)ο蠹夹g(shù)總論》由會員分享,可在線閱讀,更多相關(guān)《軟件工程與開發(fā)技術(shù)(西電第二版)第7章面向?qū)ο蠹夹g(shù)總論(179頁珍藏版)》請?jiān)谘b配圖網(wǎng)上搜索。
1、7.1概述-面向?qū)ο蠓椒ㄕ?7.2面向?qū)ο蠹夹g(shù)的基本概念 7.3面向?qū)ο蠹夹g(shù)的基本特點(diǎn) 7.4面向?qū)ο蠓治龇椒?7.5面向?qū)ο蠹夹g(shù)與程序結(jié)構(gòu) 7.6面向?qū)ο筌浖こ?7.7設(shè)計(jì)模式(Design Pattern)與框架(framework) 7.8基于構(gòu)件的軟件體系結(jié)構(gòu)(com/dcom, corba,internet) 7.9 面向?qū)ο蠓治鼋鉀Q(描述)問題的模式,第7章 面向?qū)ο蠹夹g(shù)總論,7.1 概述面向?qū)ο蠓椒ㄕ撁嫦驅(qū)ο蠹夹g(shù)的內(nèi)容包括面向?qū)ο笙到y(tǒng)分析技術(shù)、系統(tǒng)設(shè)計(jì)技術(shù)、程序設(shè)計(jì)技術(shù)、測試技術(shù)以及各種基于面向?qū)ο蠹夹g(shù)的體系結(jié)構(gòu)、框架、組件、中間件等。面向?qū)ο蠹夹g(shù)的基礎(chǔ)是面向?qū)ο蟪绦蛟O(shè)計(jì),后者
2、是程序結(jié)構(gòu)化發(fā)展的必然產(chǎn)物。眾所周知,高級程序設(shè)計(jì)語言經(jīng)歷了非結(jié)構(gòu)化、結(jié)構(gòu)化、面向?qū)ο笕齻€(gè)發(fā)展階段,這三個(gè)階段的進(jìn)化都是針對程序的結(jié)構(gòu)和系統(tǒng)分析方法而做出的。程序的結(jié)構(gòu)是指程序代碼之間的關(guān)系。每到一個(gè)新的階段,程序的結(jié)構(gòu)就更加完善、更加復(fù)雜,代碼也更容易重用,抽象程度也更高。,軟件系統(tǒng)分析方法研究將問題域(現(xiàn)實(shí)世界)向求解域(程序域)轉(zhuǎn)換和映射的方法,其目的是把問題域(現(xiàn)實(shí)世界)中的概念或者處理過程轉(zhuǎn)換或映射成程序的元素和算法。問題域(現(xiàn)實(shí)世界)相對來說是不變的或者變化較緩慢的,但系統(tǒng)分析方法卻根據(jù)程序設(shè)計(jì)方法的不同而改變,因此系統(tǒng)分析方法依賴于程序設(shè)計(jì)技術(shù),依賴于程序設(shè)計(jì)元素,參見圖7.1。
3、結(jié)構(gòu)化分析方法和面向?qū)ο蠓治龇椒▌t又分別依賴于結(jié)構(gòu)化程序設(shè)計(jì)語言和面向?qū)ο蟪绦蛟O(shè)計(jì)語言。,,圖7.1 系統(tǒng)分析方法對程序設(shè)計(jì)技術(shù)的依賴性,非結(jié)構(gòu)化分析方法就是要把問題域或現(xiàn)實(shí)世界中的概念和處理,如員工工資、計(jì)算工資等轉(zhuǎn)換成變量定義和對變量進(jìn)行處理的語句,其基本元素是變量和語句,即所謂的數(shù)據(jù)結(jié)構(gòu)+算法。由于當(dāng)時(shí)程序規(guī)模普遍比較小,運(yùn)行和應(yīng)用環(huán)境也比較單一,因此不太考慮程序結(jié)構(gòu)或者軟件結(jié)構(gòu)問題。整體來說,非結(jié)構(gòu)化技術(shù)是重視算法輕視結(jié)構(gòu)的一種方法。,,結(jié)構(gòu)化技術(shù)的基本元素是定義良好的程序結(jié)構(gòu)元素,如子程序(函數(shù))結(jié)構(gòu)和單入口/單出口的控制結(jié)構(gòu)。前者是程序的靜態(tài)結(jié)構(gòu),后者則是程序的動態(tài)結(jié)構(gòu)。子程序結(jié)構(gòu)
4、構(gòu)成了整個(gè)程序的靜態(tài)結(jié)構(gòu),是動態(tài)控制結(jié)構(gòu)的基礎(chǔ)(嚴(yán)格地說,每個(gè)語句都可以看成是對函數(shù)的調(diào)用)。結(jié)構(gòu)化分析方法就是要把問題域(現(xiàn)實(shí)世界)中的問題(概念、處理)轉(zhuǎn)換成程序中的數(shù)據(jù)結(jié)構(gòu)和子程序(函數(shù))。在這類方法中,可以認(rèn)為:程序=數(shù)據(jù)結(jié)構(gòu)+函數(shù)結(jié)構(gòu)+函數(shù)調(diào)用。相應(yīng)的數(shù)據(jù)流分析方法則將現(xiàn)實(shí)世界或者問題域中的業(yè)務(wù)處理轉(zhuǎn)換為程序的函數(shù)結(jié)構(gòu),這個(gè)過程稱為分析過程,將系統(tǒng)的結(jié)構(gòu)變成更適合于程序域的形式,比如說具有重用、高效、穩(wěn)定等特征的結(jié)構(gòu),則是設(shè)計(jì)過程。,到了面向?qū)ο蠹夹g(shù)階段,程序的基本元素是數(shù)據(jù)結(jié)構(gòu)和函數(shù)結(jié)構(gòu)的統(tǒng)一體“類”。類是程序中的靜態(tài)元素,而動態(tài)元素是對象和消息。面向?qū)ο蠓椒ㄕJ(rèn)為:程序=類結(jié)構(gòu)+對
5、象+消息。面向?qū)ο蠓治龅娜蝿?wù)則是把現(xiàn)實(shí)世界中的概念或者處理都轉(zhuǎn)換為程序域中的類和方法,將現(xiàn)實(shí)世界中的過程轉(zhuǎn)換為對象之間的交互過程。面向?qū)ο笤O(shè)計(jì)使這種類和對象交互更加適合于計(jì)算機(jī)系統(tǒng)實(shí)現(xiàn),更加合理和高效,更加容易重用。例如將員工、工資都轉(zhuǎn)換成求解域中的類,計(jì)算某位員工工資的過程稱為向該員工對象發(fā)消息。,,如上所述,新一代的程序設(shè)計(jì)語言技術(shù)并不是簡單地否定上一代語言,而是在上一代語言的基礎(chǔ)上增加新的程序結(jié)構(gòu)元素(函數(shù)、類),從而實(shí)現(xiàn)更復(fù)雜的程序結(jié)構(gòu)。這種新的程序元素更直觀、更真實(shí)、更自然、更完整地抽象了現(xiàn)實(shí)世界中的數(shù)據(jù)和處理(或者事物與概念),更好地抽象了程序中的變量和代碼,也進(jìn)一步增強(qiáng)了程序的易
6、讀性、安全性、穩(wěn)定性和重用性,同時(shí)改變了系統(tǒng)的分析和設(shè)計(jì)方法。歸根結(jié)底,程序設(shè)計(jì)語言的發(fā)展就是程序結(jié)構(gòu)以及建立在其基礎(chǔ)上的分析、設(shè)計(jì)方法的發(fā)展。,,上面的例子表明,實(shí)現(xiàn)同樣的功能可以采用不同的程序元素、程序結(jié)構(gòu)或者程序設(shè)計(jì)技術(shù)。高級的程序設(shè)計(jì)方法更擅長解決復(fù)雜的問題,因?yàn)槠涑绦蛟睾统绦蚪Y(jié)構(gòu)更為復(fù)雜。這實(shí)際上是自然界和社會系統(tǒng)的一個(gè)普遍規(guī)律,即內(nèi)部結(jié)構(gòu)決定外部功能。如果把系統(tǒng)解決的問題比做該系統(tǒng)實(shí)現(xiàn)的外部功能,而把實(shí)現(xiàn)這些功能的程序元素及其關(guān)系看做是內(nèi)部結(jié)構(gòu),越復(fù)雜的內(nèi)部結(jié)構(gòu)就預(yù)示著系統(tǒng)的功能越復(fù)雜、越強(qiáng)大,比如說,人的大腦結(jié)構(gòu)要比動物的大腦結(jié)構(gòu)復(fù)雜得多,因此其功能也要強(qiáng)大得多。,,面向?qū)ο蟮?/p>
7、程序結(jié)構(gòu)要比面向過程的程序結(jié)構(gòu)更復(fù)雜,因此可以實(shí)現(xiàn)的功能也就更加強(qiáng)大。程序設(shè)計(jì)語言技術(shù)的發(fā)展歷史充分證明了客觀和主觀系統(tǒng)進(jìn)化中,功能和結(jié)構(gòu)之間關(guān)系的一般規(guī)律。圖7.2表現(xiàn)了系統(tǒng)外部功能和內(nèi)部結(jié)構(gòu)之間的關(guān)系,其內(nèi)部結(jié)構(gòu)也是分層次的,這也符合了人認(rèn)識世界的一般規(guī)律:由外向內(nèi)、由表及里。,,圖7.2 軟件系統(tǒng)外部功能和內(nèi)部結(jié)構(gòu)之間的關(guān)系,圖7.3 軟件系統(tǒng)外部功能和內(nèi)部結(jié)構(gòu)關(guān)系的例子,,7.2 面向?qū)ο蠹夹g(shù)的基本概念7.2.1 類對象是指現(xiàn)實(shí)世界或者概念世界中的任何事物,類是具有相同結(jié)構(gòu)特征的對象的結(jié)構(gòu)抽象。此結(jié)構(gòu)特征包括對象的屬性特征和操作接口特征。屬性特征定義了所有對象都具有的屬性名稱及類型;操
8、作接口特征則定義了所有對象都具有的操作和方法。,,面向?qū)ο蟪绦蛘Z言中的類是一個(gè)代碼的預(yù)定義模塊或者程序結(jié)構(gòu)元素,類似于函數(shù)、結(jié)構(gòu)體或者記錄類型定義,其中包含了相關(guān)的變量和函數(shù)定義。類中的變量稱為屬性或者成員變量;類中的函數(shù)稱為成員函數(shù)(操作和方法)。操作和方法的區(qū)別在于:操作強(qiáng)調(diào)其操作接口,方法則強(qiáng)調(diào)實(shí)現(xiàn)方式和算法??梢园熏F(xiàn)實(shí)世界中的對象映射為程序語言中的類,有時(shí)候這種映射比較困難且不明顯,則可在其間增加一個(gè)概念世界或者概念模型。這種映射的過程即為面向?qū)ο蟮南到y(tǒng)分析,如圖7.4所示。,,圖7.4 現(xiàn)實(shí)世界向計(jì)算機(jī)世界的轉(zhuǎn)換,現(xiàn)實(shí)世界中的對象一定能夠抽象成類,但程序語言中的類則不一定有現(xiàn)實(shí)世界原
9、型。這種不對稱性反映了信息系統(tǒng)的特殊性,即程序模型并不一定是現(xiàn)實(shí)世界的原始或者簡單的等價(jià)。因?yàn)楝F(xiàn)實(shí)世界中的任何事物都可以被抽象為類,因此可以把面向?qū)ο罂闯墒且环N世界觀和方法論,在這種世界觀和方法論基礎(chǔ)上,現(xiàn)實(shí)世界被轉(zhuǎn)換成程序世界就顯得比較自然。例如:企業(yè)中的員工、倉庫、庫存帳目、商品及類別、物體、力等。,,在程序設(shè)計(jì)語言中,類是一個(gè)完整的、獨(dú)立的、可重用的,具有低耦合、高內(nèi)聚特性的程序模塊。類相當(dāng)于一種自定義數(shù)據(jù)類型,它類似于C語言中的結(jié)構(gòu)體類型(C++本身就可以使用strut關(guān)鍵字來定義類),不僅包含數(shù)據(jù)結(jié)構(gòu)也包含操作結(jié)構(gòu)。數(shù)據(jù)類型作為程序語言中進(jìn)行變量內(nèi)存分配、類型匹配、操作檢查的基礎(chǔ),為
10、程序的一致性和安全性提供了重要的保證。因此,類概念的引入從類型角度進(jìn)一步提高了程序的安全性。,,7.2.2 對象及對象實(shí)例現(xiàn)實(shí)世界中的具體事物就是對象或者對象實(shí)例,類則是對象實(shí)例的結(jié)構(gòu)抽象。每個(gè)對象實(shí)例一般具有三方面的特性(亦稱對象“三要素”):(1) 確定的標(biāo)識,能夠被唯一地確認(rèn)。(2) 具有一定的屬性,表示其性質(zhì)或狀態(tài)。(3) 具有一定的行為能力或者操作能力,可給外界提供服務(wù)或者通過操作改變其狀態(tài)。,,對象標(biāo)識也是對象屬性之一,是一類特殊的屬性,類似于實(shí)體關(guān)系模型中的主碼。應(yīng)當(dāng)注意,對象標(biāo)識和對象在程序中的標(biāo)識是不一樣的,前者是對象本身的固有屬性,后者是在程序空間中給該對象起的名字,僅供程
11、序中使用?,F(xiàn)實(shí)世界中的任何事物都可以抽象成對象,例如具有具體物質(zhì)形態(tài)的對象,如員工、計(jì)算機(jī)、汽車等;具有抽象物質(zhì)形態(tài)的對象,如銀行賬戶、力等。,,面向?qū)ο蟊旧砭褪且环N世界觀以及由此派生的方法論,是一種觀察世界和認(rèn)識世界的方式。在面向?qū)ο蟮氖澜缬^中,世界是由對象及其關(guān)系組成的,對象是由屬性和行為組成的,對象之間具有各種各樣的聯(lián)系。類是對象結(jié)構(gòu)的抽象,關(guān)系是對象之間聯(lián)系的抽象。對象世界的發(fā)展變化過程就是對象之間的交互過程(面向過程也是一種世界觀,認(rèn)為世界是由過程組成的,每個(gè)過程都有自己的目標(biāo)和處理的對象)。面向?qū)ο蟮氖澜缬^中的屬性和操作剛好對應(yīng)了程序世界中保存數(shù)據(jù)或者狀態(tài)的變量和實(shí)現(xiàn)一定功能的函數(shù)
12、。屬性是事物的性質(zhì)和狀態(tài)描述;行為是對屬性的操作,可以對外提供服務(wù),屬性則是行為的基礎(chǔ)和操作的內(nèi)容。,,根據(jù)屬性和行為的側(cè)重點(diǎn)不同,對象又可以分成實(shí)體對象和過程對象,前者強(qiáng)調(diào)對象的狀態(tài)描述,例如“學(xué)生”對象;后者強(qiáng)調(diào)對象的過程特性,例如“流程”對象?,F(xiàn)實(shí)世界中的事物都是有聯(lián)系的,對象之間也有聯(lián)系。例如對象間的組成關(guān)系:如汽車對象是由零件對象組成的;關(guān)聯(lián)關(guān)系(信息聯(lián)系):如老板有員工的聯(lián)系方式。對象之間有些聯(lián)系是暫時(shí)的:如某人向你問了一下路(發(fā)送消息),你向其提供了服務(wù);有些聯(lián)系則是永恒的、持久的:如父母、子女之間的關(guān)系;有些則是介于兩者之間的:如配偶關(guān)系等。,,從靜態(tài)角度來看,對象實(shí)際上就是由
13、類(包括數(shù)據(jù)結(jié)構(gòu)和函數(shù)結(jié)構(gòu)定義)模板派生的變量;從動態(tài)角度來看,對象之間的交互(包括自交互)完成或者實(shí)現(xiàn)了功能。在面向?qū)ο蟪绦蛑?,類是一種代碼模板定義,它類似于函數(shù)結(jié)構(gòu)和數(shù)據(jù)結(jié)構(gòu),必須要實(shí)例化才能使用。實(shí)例化就是使用類創(chuàng)建具體的對象變量(也叫對象實(shí)例),由類產(chǎn)生對象變量相當(dāng)于在工廠中使用模具生產(chǎn)產(chǎn)品。在程序中只有創(chuàng)建了具體的對象變量,系統(tǒng)才會給其分配內(nèi)存,程序才能訪問其屬性和操作。,,由于對象變量占用的內(nèi)存空間不固定,其內(nèi)存分配方式多采用動態(tài)分配和回收機(jī)制。在面向?qū)ο蟪绦蛟O(shè)計(jì)語言中,除了對象變量本身,還有一種引用變量(reference variable),其本質(zhì)上是指針或者地址,可以指向?qū)ο?/p>
14、變量,其類型必須是一致的。通過引用變量訪問對象變量簡化了對動態(tài)分配的對象內(nèi)存空間的訪問。如Student是Java語言中定義的類,語句Student s = new Student();聲明了一個(gè)引用變量s,創(chuàng)建了一個(gè)對象變量new Student(),并通過賦值語句將該對象變量所在的內(nèi)存區(qū)域的首地址存放到s中,通過s可以對此內(nèi)存區(qū)域進(jìn)行操作。一般來說,引用變量和對象變量是在不同的內(nèi)存空間中,前者存放在堆??臻g中,后者是放在堆空間中,這兩種內(nèi)存空間所允許的操作是有所不同的(如圖7.5所示)。,,圖7.5 引用變量和對象變量之間的關(guān)系,7.2.3 消息機(jī)制純面向?qū)ο蟪绦蛟O(shè)計(jì)語言如Java中,所有
15、的函數(shù)或者操作都依附于一個(gè)對象主體,這種依附于某個(gè)對象的函數(shù)叫做成員函數(shù)或者對象操作(方法)。在純面向?qū)ο蟪绦蛑校瑢θ魏我粋€(gè)函數(shù)的調(diào)用都是對某個(gè)對象的方法調(diào)用,同時(shí)會把該對象的信息(一般是內(nèi)存地址)傳遞給被調(diào)用函數(shù),這就是函數(shù)的實(shí)例化過程。在面向?qū)ο蟪绦蛑?,調(diào)用一個(gè)對象的方法或者操作叫做向該對象發(fā)消息,調(diào)用者叫做消息發(fā)出者,被調(diào)用者叫做消息接受者。消息、事件和函數(shù)調(diào)用或者事件響應(yīng)是相輔相承的。程序中,消息就是現(xiàn)實(shí)世界中的請求或者通知事件,這一般都是通過對系統(tǒng)執(zhí)行一定的操作完成的。對該請求或者通知可以響應(yīng),也可以不響應(yīng),響應(yīng)可以是同步的,也可以是異步的。,例如,客戶如果想從ATM機(jī)中取錢,通常會
16、按下取錢按鍵,這實(shí)際上就是向ATM機(jī)發(fā)送了取錢消息,也是向ATM機(jī)發(fā)送了取錢請求,ATM機(jī)會顯示一個(gè)取錢界面,讓用戶輸入取款數(shù)額,這是通過ATM機(jī)的一個(gè)方法或者操作實(shí)現(xiàn)的。用戶輸入取款金額后按下確定鍵,相當(dāng)于又向ATM機(jī)發(fā)送新的消息,導(dǎo)致ATM機(jī)的另一個(gè)方法的調(diào)用,通常在該方法中又會向其他對象發(fā)送消息,例如該客戶的賬戶Account對象,通過調(diào)用該賬戶對象的draw()操作實(shí)現(xiàn)賬戶上資金的更新。用戶通過和ATM機(jī)一系列的請求/響應(yīng)的交互活動完成了執(zhí)行系統(tǒng)的某個(gè)功能,如取錢??蛻魧ο?、ATM對象、Account對象之間的消息交互見圖7.6。,,圖7.6 消息機(jī)制,,7.3 面向?qū)ο蠹夹g(shù)的基本特點(diǎn)
17、7.3.1 封裝性程序的基本元素是變量定義以及對變量的處理。對于規(guī)模比較小的程序,每個(gè)變量的意義和訪問都由程序員自己控制,但對于需要多人長時(shí)間開發(fā)的大規(guī)模程序,存在訪問其他人定義的變量的情況,這時(shí)候變量的安全性則成為問題。程序中有很多錯(cuò)誤都是由于錯(cuò)誤地訪問了不該訪問的變量而引起的。面向過程程序設(shè)計(jì)語言中的函數(shù)結(jié)構(gòu)中的局部變量在一定程度上解決了這個(gè)問題,但是全局?jǐn)?shù)據(jù)結(jié)構(gòu)或者變量中還是存在不安全的訪問問題。面向?qū)ο蟪绦驅(qū)⒋鎯?shù)據(jù)的變量和對數(shù)據(jù)(變量)的處理(方法)封裝起來(私有化),從程序外部不能直接訪問數(shù)據(jù),而必須通過對外公開的方法進(jìn)行訪問,這就避免了對正確數(shù)據(jù)的錯(cuò)誤操作,如圖7.7所示。,,圖
18、7.7 對象的封裝性,將Account對象中表示余額的屬性balance(實(shí)型變量)隱藏起來,對外部程序不可見,外部程序只能通過公開的方法save ( )或者draw ( )來改變balance的值,這樣就可以避免外部程序?qū)ζ溥M(jìn)行錯(cuò)誤的操作。比如說:在程序中直接對balance變量做乘除法操作(例如實(shí)現(xiàn)存錢操作時(shí)將“+”敲成“*”號),而編譯程序是沒有辦法發(fā)現(xiàn)此錯(cuò)誤的,因?yàn)閷τ趯?shí)型變量來說,不能限制對其做乘除操作,從語法上來看這些都是合法的操作。對于賬戶余額來說,乘除法則是無意義的操作。因此可以通過隱藏?cái)?shù)據(jù),公開合法的操作接口來限定賬戶這種對象的內(nèi)涵和外延,增加程序的安全性。,,面向?qū)ο蟮姆庋b
19、性實(shí)現(xiàn)的是信息隱藏。僅將需要向外公開的方法和屬性向外公開;所有不需要向外公開的方法和屬性都被隱藏起來。正像電視機(jī)一樣,內(nèi)部電路元件對用戶都隱藏起來,對外只公開用戶可用的接口,如開關(guān)、音量調(diào)節(jié)、調(diào)臺等。這種封裝性通過定義合適的操作接口來進(jìn)一步確定事物的本質(zhì)特征。對于傳統(tǒng)的面向過程的程序設(shè)計(jì)語言來說,表示銀行存款和圖形尺寸時(shí)都是使用實(shí)型變量,沒有區(qū)別,但實(shí)際上對這兩種量的操作是有區(qū)別的。很明顯,銀行存款只允許增加、減少或者查詢;對尺寸來說卻能按比例放大或者縮小,即執(zhí)行乘除法。類似的還有數(shù)據(jù)結(jié)構(gòu)中的例子,保存線性表、堆棧、隊(duì)列元素的數(shù)據(jù)存儲結(jié)構(gòu)可以是一樣的,但對其允許的操作是不一樣的。封裝性增強(qiáng)了程
20、序中變量的安全性,同時(shí)也增強(qiáng)了程序中數(shù)據(jù)類型、數(shù)據(jù)結(jié)構(gòu)和變量的語義內(nèi)涵,提高了程序分析方法的直觀性。,7.3.2 繼承性軟件重用技術(shù)始終是軟件開發(fā)技術(shù)研究中的一個(gè)重要課題,從程序行的簡單復(fù)制到宏替換,從數(shù)據(jù)結(jié)構(gòu)定義再到函數(shù)定義,從類的定義到類的繼承,從構(gòu)件到框架等,都是代碼重用技術(shù)的體現(xiàn)。繼承機(jī)制是一種高級的代碼重用技術(shù),子類自動繼承父類的所有代碼并且可以進(jìn)行任意的覆蓋和擴(kuò)充。如圖7.8所示,子類研究生繼承了父類學(xué)生中的屬性和操作,又?jǐn)U充了新的屬性和操作。子類和父類保持一種動態(tài)關(guān)系:當(dāng)父類代碼改變的時(shí)候,子類繼承的那部分代碼會自動修改,即子類對父類的繼承不是簡單的復(fù)制,而是動態(tài)的鏈接,子類和父
21、類始終保持一種聯(lián)系,這是一種與生俱來的、靜態(tài)的聯(lián)系,一旦定義,則無法改變。,,子類對父類的擴(kuò)充包括對父類同名屬性和方法的覆蓋以及增加新的屬性和方法。過多的繼承層次會使程序結(jié)構(gòu)變得異常復(fù)雜、難以理解并且難以維護(hù)。子類不僅僅繼承了父類的代碼,也繼承了父類的類型,或者說和父類型是相容的。程序設(shè)計(jì)語言中的繼承關(guān)系區(qū)別于生物界中的遺傳關(guān)系,如父子關(guān)系,更像事物分類中的分類關(guān)系。父類往往是各子類的共性的抽象,是對所有子類對象的抽象。例如:汽車、自行車、三輪車的父類是車,車是一個(gè)抽象的概念,凡是具有輪子可以滾動行走的物體都可以稱為車。又比如三角形、矩形、圓等具體圖形的父類可以定義為圖形類等。圖7.8中,研究
22、生屬于學(xué)生中的一種,是特殊的學(xué)生,因此是從一般到特殊的分類關(guān)系。,圖7.8 類的繼承關(guān)系,7.3.3 多態(tài)性多態(tài)性(polymorphism)是指同一種事物可以有多種不同的形態(tài)或者含義,也可以認(rèn)為是從不同的角度觀察同一事物,可以得到不同的視圖。在面向?qū)ο蟪绦蛟O(shè)計(jì)語言中,多態(tài)性有三種含義。多態(tài)的第一種含義是方法的重載(Overload),在同一個(gè)類中可以存在同名不同參數(shù)的操作,這些操作的具體實(shí)現(xiàn)是不同的,即同名方法在不同的參數(shù)情況下有不同的實(shí)現(xiàn)。這反映了客觀世界中對事物操作的復(fù)雜性和聯(lián)系性,如對銀行來說,存錢是一種操作,但根據(jù)用戶出示的是存折還是銀行卡,其具體的實(shí)現(xiàn)有所不同。編譯程序通過參數(shù)類型
23、或者個(gè)數(shù)來確定具體調(diào)用哪個(gè)方法,因?yàn)檫@種多態(tài)性是在編譯階段完成的,所以可以稱為靜態(tài)的多態(tài)性或者編譯期多態(tài)性。操作符重載也是基于這種多態(tài)性的。例如圓對象可以根據(jù)不同的初始條件進(jìn)行構(gòu)造,見下面代碼。,class Circle public Circle(double x,double y,double r) //已知圓心坐標(biāo)和半徑 public Circle(Point center,double r) //已知圓心和半徑 public Circle(double x1,double y1,double x2,double y2,double x3,double y3)//已知圓上三點(diǎn)坐標(biāo) pu
24、blic Circle(Point p1,Point p2,Point p3) //已知圓上三點(diǎn) public Circle(Point p1,Point p2,double r) //已知圓上兩點(diǎn)和半徑 ,,下面是引用上述定義創(chuàng)建圓對象的代碼:Circle c1 = new Circle(); //創(chuàng)建一個(gè)默認(rèn)的圓對象Circle c2 = new Circle(new Point(2,2),5); //創(chuàng)建已知圓心和半徑的圓對象Circle c3 = new Cirlce(0,0,2,3,4,5); //創(chuàng)建已知圓上三點(diǎn)坐標(biāo)的圓上述代碼中同名方法具有不同的參數(shù),給出了在不同初始條件下構(gòu)建
25、圓對象的方法。,,多態(tài)的第二種含義是子類對父類的方法進(jìn)行覆蓋(override),程序會根據(jù)當(dāng)前對象狀態(tài)而自動調(diào)用父類或者子類對象的方法。這一點(diǎn)和下面講的多態(tài)性的第三種含義本質(zhì)上是相同的。這種多態(tài)性由于在運(yùn)行期間才能確定,因此稱為動態(tài)的多態(tài)性或者運(yùn)行期多態(tài)性。,,例如:Shape是圖形類,Circle是其子類,父類和子類的方法getArea()具有不同的實(shí)現(xiàn)。public class Shape double getArea()return 0.0;public class Circle extends Shape double r; double getArea()return Math.P
26、I * r * r;,,上面類的對象實(shí)例創(chuàng)建代碼Shape s = new Circle()將子類對象實(shí)例賦值給父類的引用變量(這一點(diǎn)正是類型的多態(tài)性,本節(jié)后面詳細(xì)解釋),那么s.getArea()方法將調(diào)用父類還是子類的方法呢?按照類型分析,s是Shape類型,則s.getArea()方法應(yīng)該是Shape的方法,但是s實(shí)際上指向的是Circle對象,所以s.getArea()方法應(yīng)該是Circle的方法,但這是在運(yùn)行期間才能確定的,因?yàn)閟具體指向的對象只有在運(yùn)行期才能確定。不同的語言在此處有不同的處理方法。在C++中,上述代碼調(diào)用的是Shape的getArea()方法,但是如果在Shape的
27、getArea方法定義前面加上virtual關(guān)鍵字,即:virtual public double getArea();,,則同樣的代碼s.getArea()調(diào)用的方法是子類Circle的方法。方法定義前面加上virtual的意思是指該方法的具體執(zhí)行代碼直到運(yùn)行期才能確定。在Java中,對象的方法默認(rèn)都是運(yùn)行期確定的,因此s.getArea()一定是調(diào)用s實(shí)際指向的對象的方法,即Circle對象的方法。如果要想調(diào)用父類的area()方法,只需要讓s指向父類對象即可:Shape s = new Shape();這種運(yùn)行期確定方法的執(zhí)行代碼正如運(yùn)行期分配或者刪除對象空間一樣,是非常靈活高效的,所以
28、Java取其作為語言的默認(rèn)特性,這也是Java語言簡潔高效且能迅速普及的原因之一。,,多態(tài)的第三種含義是類型的多態(tài)或者類型造型(type cast),前者是指一個(gè)對象可以看成是多種類型,后者是指子類對象可以造型成父類型,即將子類對象看成是父類類型,類似于類型強(qiáng)制,注意只是“看成”是父類類型,而不是真正的父類對象,子類對象永遠(yuǎn)不能變成父類對象,而只能扮演成父類對象,以通過程序語法的類型匹配檢查,但其本質(zhì)上還是子類對象。這在生活實(shí)際中也是經(jīng)常遇到的,例如一個(gè)研究生去應(yīng)聘,如果企業(yè)只招聘本科生的話,他也可以將自己看成是本科生而降級使用,但他自己本質(zhì)上還是研究生。除了子類對象可以扮演(造型)成父類類型
29、外,某個(gè)類的對象也可以造型成該類實(shí)現(xiàn)的接口類型。,,造型的方法就是將該類對象賦值給某種類型的引用變量,如:A obj = new B(),B要么實(shí)現(xiàn)A接口,要么B是A的子類。定義引用變量并沒有創(chuàng)建對象,相當(dāng)于定義了一種類型約束。在面向?qū)ο笳Z言中,這種造型稱為向上造型(upcast),它是安全的,因?yàn)樽宇愋涂隙M足父類型的要求,子類型要么等于父類型,要么大于父類型(擴(kuò)充)。從類的現(xiàn)實(shí)世界語義來看,子類和父類的關(guān)系是ISA(讀作“是一個(gè)”)關(guān)系,即子類對象首先是一個(gè)父類。圖7.9中的關(guān)系讀作研究生是一個(gè)學(xué)生,這無疑是客觀正確和可理解的。從哲學(xué)概念上來看,子類和父類正反映了特殊和一般、個(gè)性和共性的關(guān)
30、系,一般性寓于特殊性之中,共性寓于個(gè)性之中。這是面向?qū)ο蠹夹g(shù)中繼承或者接口概念的本質(zhì),這也是只有具有繼承或者實(shí)現(xiàn)接口關(guān)系的對象才能造型的原因。,,圖7.9 ISA關(guān)系,數(shù)據(jù)類型在程序設(shè)計(jì)語言中的重要性毋庸置疑,它是內(nèi)存分配、類型檢查、操作檢查的基礎(chǔ)。程序語言中數(shù)據(jù)類型的多少是衡量該語言功能是否強(qiáng)大的依據(jù)之一,現(xiàn)在的程序語言都提供了大量標(biāo)準(zhǔn)數(shù)據(jù)類型以及自定義數(shù)據(jù)類型的機(jī)制。在面向?qū)ο蟪绦蛟O(shè)計(jì)語言中,類可以看成是一種自定義類型。類型檢查也是程序安全性檢查機(jī)制之一,通過檢查相關(guān)操作的類型匹配可以發(fā)現(xiàn)很多不兼容的錯(cuò)誤。比如:賦值操作、各種運(yùn)算操作,如果沒有類型檢查的話,將會出現(xiàn)很多程序員難以察覺的錯(cuò)誤
31、,這也是過去類型檢查機(jī)制較弱的弱類型語言(如C語言)容易出錯(cuò)的原因。,,面向?qū)ο髾C(jī)制中類的定義實(shí)際上增強(qiáng)了類型檢查的安全性,一個(gè)類就相當(dāng)于一種自定義的數(shù)據(jù)類型,不同類定義的變量是不允許相互賦值的,這雖然增強(qiáng)了程序的安全性,但卻帶來了另外一個(gè)問題,那就是代碼效率很低,針對每一個(gè)事物都需要定義一個(gè)類,例如定義堆棧類就得針對不同的元素類型定義多個(gè)類,每個(gè)類只能接收一種類型元素。C++采用一種叫做模板(template)的機(jī)制來處理這個(gè)問題,而Java則采用多態(tài)性來解決這個(gè)問題。多態(tài)(polymorphism)的原意就是同一個(gè)事物可以具有多種狀態(tài),或者說同一個(gè)事物在不同的場合、從不同的角度可以看成是不
32、同的東西,這是客觀事物復(fù)雜性的程序表現(xiàn)。,,7.3.4 抽象性抽象是人類思維的本質(zhì)特性之一。抽象性是對復(fù)雜事物本質(zhì)和特性的提煉和概括的能力,可以說沒有抽象就沒有理論思維,就沒有指導(dǎo)認(rèn)識世界改造世界的一般性結(jié)論,也就沒有系統(tǒng)分析和設(shè)計(jì)。在程序中始終存在著抽象性,數(shù)據(jù)類型是數(shù)據(jù)結(jié)構(gòu)和操作接口的抽象,常量是程序中常數(shù)的抽象,變量是程序中變化的數(shù)據(jù)的抽象,函數(shù)是實(shí)現(xiàn)某個(gè)功能或者處理代碼的抽象,類是多個(gè)實(shí)例對象結(jié)構(gòu)(屬性和操作接口)共性的抽象,抽象類或者接口又是多個(gè)類公共接口的抽象。,,面向?qū)ο蠹夹g(shù)將抽象性引入到代碼的實(shí)現(xiàn)中,可以實(shí)現(xiàn)很多更抽象、更一般、更統(tǒng)一的方法。比如說:Shape是所有圖形對象的父
33、類,是抽象的,則方法getArea(Shape s)可以返回任何圖形的面積,totalArea(Shape s)則可以返回任意多個(gè)任意圖形的面積和,draw(Shapes)則可以畫出任意多個(gè)任意圖形。注意:這些方法本身都具有抽象性、一般性的含義。當(dāng)然,這些抽象的方法并沒有真正去實(shí)現(xiàn)計(jì)算每個(gè)具體圖形的面積或者畫出具體的圖形,而只是完成通用的操作,如對所有的圖形進(jìn)行求和或者畫出所有的圖形(兩者都是對集合進(jìn)行遍歷),而把具體的操作都交給具體的子類(如圓、矩形)來實(shí)現(xiàn)。在面向?qū)ο蟪绦蛟O(shè)計(jì)語言中,抽象類、接口或者模板類都很好地實(shí)現(xiàn)了抽象的功能。,,由于程序中引入了抽象的操作,因此使得程序結(jié)構(gòu)出現(xiàn)依賴倒置
34、的現(xiàn)象。過去結(jié)構(gòu)化分析方法得到的系統(tǒng)結(jié)構(gòu)是自上而下、逐步求精,上層抽象的模塊依賴于下層具體的模塊,上層模塊通過調(diào)用下層模塊完成任務(wù),或者說先有下層模塊,才有上層模塊。面向?qū)ο蟪绦虻睦^承結(jié)構(gòu)中則是下層依賴于上層,因?yàn)樯蠈邮歉割?,下層是子類,先有上層再有下層,因此程序變得更抽象。程序結(jié)構(gòu)依賴性對比如圖7.10所示,左邊部分的每個(gè)矩形框是函數(shù),右邊部分的每個(gè)矩形框是類。,,圖7.10 頂層模塊和底層模塊之間的依賴關(guān)系,,7.4 面向?qū)ο蠓治龇椒ㄏ到y(tǒng)分析方法就是把現(xiàn)實(shí)世界或者問題域中的概念和過程轉(zhuǎn)換成求解域或程序域中元素的方法。因此系統(tǒng)分析方法是和程序域元素密切相關(guān)的。結(jié)構(gòu)化或者面向過程的分析方法是把
35、現(xiàn)實(shí)世界或者問題域中的過程處理抽象成概念模型中的數(shù)據(jù)輸入、數(shù)據(jù)處理和結(jié)果輸出,然后將處理過程轉(zhuǎn)換成程序結(jié)構(gòu)中的函數(shù)。程序中的函數(shù)有些是直接來自于現(xiàn)實(shí)世界中的處理過程,如計(jì)算工資,但僅靠現(xiàn)實(shí)世界中的處理過程是不夠的,在程序中還有很多處理過程是和計(jì)算機(jī)或者程序本身密切相關(guān)的,如輸入數(shù)據(jù)的過程等。,,面向?qū)ο蟮姆治龇椒ň褪前熏F(xiàn)實(shí)世界或者問題域中的事物、概念、過程等抽象成概念模型中的對象或類,然后轉(zhuǎn)換成程序語言中的對象或類。程序語言中的類概念本身也來自于現(xiàn)實(shí)世界中的對象,因此概念模型中的類和程序語言中的類是一致的。但是僅靠現(xiàn)實(shí)世界中的類是不夠的,作為信息系統(tǒng)或者程序模型,本身也有自己獨(dú)特的機(jī)制和規(guī)律,
36、具有區(qū)別于現(xiàn)實(shí)世界或者問題域的特點(diǎn),例如每個(gè)程序都具有一定的運(yùn)行環(huán)境和操作界面等,這些因素也被抽象為系統(tǒng)中的類,視為系統(tǒng)類。現(xiàn)實(shí)世界中抽取的類一般稱為業(yè)務(wù)類或者領(lǐng)域類,即在現(xiàn)實(shí)世界中存在有原型的類。業(yè)務(wù)類又可以分為分析類和設(shè)計(jì)類,前者是從現(xiàn)實(shí)世界中直接抽取的類,后者是對分析類的抽象、包裝、組合、擴(kuò)充和修飾,如設(shè)計(jì)模式中的一些父類、實(shí)用類等。,按照目前廣泛流行的MVC模式,現(xiàn)實(shí)世界中的類相當(dāng)于模型類(Model),確定了現(xiàn)實(shí)世界事物本身的邏輯、聯(lián)系和規(guī)律等,如學(xué)生、職工、工資、力等。其他的類,如表現(xiàn)類(View),則是對模型數(shù)據(jù)的計(jì)算機(jī)表現(xiàn),是人機(jī)接口界面類;控制類(Control)則控制系統(tǒng)的
37、運(yùn)行流程。,,從系統(tǒng)的頂層結(jié)構(gòu)到系統(tǒng)的微觀結(jié)構(gòu)中,MVC結(jié)構(gòu)都是存在的,例如:Struts框架結(jié)構(gòu)是系統(tǒng)的整體架構(gòu),是符合MVC模式的,而Java的圖形界面swing組件類本身也是按照MVC模式設(shè)計(jì)的。MVC模式實(shí)際上給出了構(gòu)建信息系統(tǒng)的一種過程和方法:即從業(yè)務(wù)對象到系統(tǒng)對象,從業(yè)務(wù)模型到系統(tǒng)模型的演化過程。首先抽象現(xiàn)實(shí)世界中的相關(guān)對象,稱為業(yè)務(wù)對象,在此基礎(chǔ)上添加對其的表現(xiàn)類即視圖類,系統(tǒng)流程(宏觀)和業(yè)務(wù)流程(微觀)的控制則轉(zhuǎn)換成控制類。一般來說,業(yè)務(wù)類可以做到與實(shí)現(xiàn)環(huán)境或者實(shí)現(xiàn)語言無關(guān),但界面類或者系統(tǒng)控制類則可能和實(shí)現(xiàn)環(huán)境及實(shí)現(xiàn)語言有關(guān)。從現(xiàn)實(shí)世界對象模型到系統(tǒng)對象模型的演化過程如圖7
38、.11所示,系統(tǒng)對象中最上層的是業(yè)務(wù)對象,第二層是控制對象,最底層是界面對象。,,圖7.11 現(xiàn)實(shí)世界的對象模型向程序世界的對象模型轉(zhuǎn)換舉例一,有些系統(tǒng)模型的類會更多一些,另一個(gè)現(xiàn)實(shí)世界模型向程序世界模型轉(zhuǎn)換的例子超市購物向網(wǎng)上購物網(wǎng)站的轉(zhuǎn)換,其中,業(yè)務(wù)模型包括產(chǎn)品(Product)、購物車(Cart)、訂單(Order)和客戶(User)四種;系統(tǒng)模型類包括產(chǎn)品(Product)、購物車(Cart)、訂單(Order)、訂單數(shù)據(jù)庫(DB Order)和客戶(User)五種。從業(yè)務(wù)世界模型向程序世界模型轉(zhuǎn)換的示意圖如圖7.12所示。,,圖7.12 現(xiàn)實(shí)世界的對象模型向程序世界的對象模型轉(zhuǎn)換舉例
39、二,,7.5 面向?qū)ο蠹夹g(shù)與程序結(jié)構(gòu)7.5.1 概述程序?qū)ν馓峁┑墓δ苁瞧渫獠刻匦?,?nèi)部也有著自己獨(dú)特的結(jié)構(gòu),即程序結(jié)構(gòu)。程序中具有完整語義的最小語法單位是表達(dá)式,語句是程序執(zhí)行的最小單位,語句的集合組成了程序。語句相當(dāng)于原子,語句與語句之間的關(guān)系形成程序結(jié)構(gòu),如順序、選擇、循環(huán)。數(shù)據(jù)結(jié)構(gòu)、函數(shù)定義也是一種程序結(jié)構(gòu),稱為程序模塊,它由完成某個(gè)特定功能的多條語句組成。模塊的類型包括數(shù)據(jù)模塊、算法模塊或者二者的綜合。程序模塊是作為一個(gè)整體存在的,可以獨(dú)立地開發(fā)存儲,具有獨(dú)立性、安全性、語義性和重用性。其中數(shù)據(jù)模塊類似于數(shù)據(jù)結(jié)構(gòu)定義,比如C語言中的結(jié)構(gòu)體;算法(程序)模塊類似于函數(shù)。數(shù)據(jù)和算法(程序
40、)的綜合就是面向?qū)ο蟪绦蛑械念悺?,在程序從非結(jié)構(gòu)化到結(jié)構(gòu)化再到面向?qū)ο蟮倪M(jìn)化過程中,程序結(jié)構(gòu)越來越復(fù)雜、越來越豐富、重用粒度越來越大、結(jié)構(gòu)層次也越來越深,對外呈現(xiàn)的功能也越來越強(qiáng)大。其內(nèi)部結(jié)構(gòu)和外在表現(xiàn)之間的關(guān)系符合自然界和社會進(jìn)化的一般規(guī)律,即內(nèi)部結(jié)構(gòu)越復(fù)雜,其對外呈現(xiàn)的功能也就越強(qiáng)大。但是,這種內(nèi)部結(jié)構(gòu)必須是建立在一種優(yōu)化合理的基礎(chǔ)上,而不是簡單的堆積。目前的包類函數(shù)的層次結(jié)構(gòu)就是一種公認(rèn)的優(yōu)化合理結(jié)構(gòu)。,,程序結(jié)構(gòu)中包含靜態(tài)的結(jié)構(gòu)和動態(tài)的結(jié)構(gòu)。靜態(tài)的結(jié)構(gòu)就是程序代碼之間的關(guān)系,如類的繼承、關(guān)聯(lián)關(guān)系等,是代碼定義階段的關(guān)系;動態(tài)結(jié)構(gòu)是函數(shù)的調(diào)用或者向?qū)ο蟀l(fā)消息的過程,是代碼執(zhí)行時(shí)的關(guān)系。
41、動態(tài)結(jié)構(gòu)要以靜態(tài)結(jié)構(gòu)為基礎(chǔ)。圖7.13和圖7.14分別表示了面向過程和面向?qū)ο蟪绦蛑g的靜態(tài)結(jié)構(gòu)關(guān)系和動態(tài)結(jié)構(gòu)關(guān)系,從圖中可以看出,面向?qū)ο蟪绦虻慕Y(jié)構(gòu)要比面向過程程序的結(jié)構(gòu)復(fù)雜得多。,,軟件工程的實(shí)踐證明,程序的結(jié)構(gòu)是通過不斷的改進(jìn)而得到優(yōu)化的,不會一步到位。好的程序結(jié)構(gòu)可以通過有經(jīng)驗(yàn)的開發(fā)人員在設(shè)計(jì)階段通過精心設(shè)計(jì)而得到,也可以通過對已有的結(jié)構(gòu)中不太好的代碼進(jìn)行不斷改進(jìn)而得到。通過代碼改進(jìn)程序結(jié)構(gòu)的方法也稱為“重構(gòu)”。由于重構(gòu)是從質(zhì)量欠佳的代碼基礎(chǔ)進(jìn)行改進(jìn)的,而不是一下拿出高質(zhì)量的結(jié)構(gòu)設(shè)計(jì),因此這種方法更受初學(xué)者的歡迎,也越來越受到軟件界的重視,目前幾乎所有的主流開發(fā)環(huán)境都提供了對重構(gòu)工具的
42、支持。,,圖7.13 結(jié)構(gòu)的層次靜態(tài)結(jié)構(gòu),圖7.14 程序執(zhí)行的線索動態(tài)結(jié)構(gòu),7.5.2 重構(gòu)重構(gòu)(Refactor)是指在不改變代碼的外在功能的前提下重新設(shè)計(jì)已有代碼,以獲取代碼新的特性。這里新的特性主要就是由于結(jié)構(gòu)的改進(jìn)而帶來的高效性、安全性、穩(wěn)定性、可維護(hù)性和可擴(kuò)充性等。根據(jù)上一小節(jié)中所描述的程序結(jié)構(gòu)的改進(jìn)過程可以看出,這種重構(gòu)是完全可能的,也是很有必要的。根據(jù)外在功能和內(nèi)部結(jié)構(gòu)的關(guān)系來看,重構(gòu)的目的主要在于改進(jìn)程序結(jié)構(gòu)。需要注意的是,重構(gòu)不是整體重新建造(Reconstructor),可能只是局部的修改(Refactor),如把一些代碼抽象成方法,以提高程序結(jié)構(gòu)的粒度,增加重用度。甚至
43、可能只是非常簡單的重命名,以改善程序的可讀性等。重構(gòu)對于那些沒有做充分的設(shè)計(jì)而直接編碼的軟件開發(fā)過程而言是非常有效的。,,常見的重構(gòu)方法有:提取方法(Extract Method)、引入父類(Introduce Super Class)或者接口(Interface)、屬性和方法上移或者下移(Attribute or Method Move up or Move down)等。重構(gòu)所影響的程序范圍可能很小或者很大,但是即使最小的變化也可能引入bug。一處修改可能導(dǎo)致整個(gè)代碼變化,所以重構(gòu)后必須要測試所有可能受影響的地方,這樣才能保證對外的功能不會改變。,,重構(gòu)的種類有很多,重構(gòu)的工作量有時(shí)候也會
44、很大,尤其是當(dāng)現(xiàn)存代碼比較多的時(shí)候。目前主流的開發(fā)環(huán)境如Eclipse、Microsoft Visual Studio 2005等,都提供自動進(jìn)行重構(gòu)的工具。當(dāng)然,不同的語言和開發(fā)環(huán)境提供的重構(gòu)工具種類會有所不同,下面列舉了一些常見的重構(gòu)方法:(1) try/catch重構(gòu):將普通代碼塊置于try/catch塊中,將代碼的正常執(zhí)行過程和錯(cuò)誤處理過程分離開來,可以增加代碼的安全性和魯棒性。,,(2) 重命名(Rename)和移動(Move):由于各種可能的原因,對現(xiàn)存代碼中的包、類、接口、方法、屬性或域變量、局部變量等進(jìn)行重新命名,同時(shí)對所有相關(guān)的引用(reference)都作相應(yīng)的修改。該重構(gòu)
45、還包括移動類和包進(jìn)行重構(gòu)的方法。即將包或者類從現(xiàn)有的位置移到另外的包中,或把靜態(tài)成員從一個(gè)類中移到另外的類中。這些重構(gòu)方法都屬于靜態(tài)的結(jié)構(gòu)重構(gòu),也可以在設(shè)計(jì)階段針對模型進(jìn)行。如果在設(shè)計(jì)階段進(jìn)行此類重構(gòu),則需要重新進(jìn)行正向工程(Forward Engineering),而且原來的代碼會自動注釋掉,需要重新編碼。如果在代碼環(huán)境中進(jìn)行重構(gòu),則會自動實(shí)現(xiàn)重構(gòu)之后的所有代碼。,,(3) 引入常量、變量和方法(Introduce Constant and Variable,Extract Method):將程序中的常數(shù)定義成常量、表達(dá)式定義成變量、代碼片斷定義成方法都是代碼結(jié)構(gòu)的改進(jìn)。也可以把局部變量轉(zhuǎn)換
46、成屬性變量,即全局變量。(4) 改變方法參數(shù)(Change Method Parameter):方法的參數(shù)是方法簽名的一部分,是方法調(diào)用中動態(tài)變化的地方。修改參數(shù)實(shí)際上就是修改方法簽名。在提取方法重構(gòu)中,可以將方法中表達(dá)式代碼中的常數(shù)、變量或者表達(dá)式轉(zhuǎn)換成方法參數(shù),這樣該方法就具有更一般的意義。,,(5) 泛化類型(Generalize Type):使用父類型代替子類型。這樣的程序更具有一般性,更能適應(yīng)變化。例如:定義一個(gè)集合類型變量,使用ArrayList v= new ArrayList(); 重構(gòu)成List v = new ArrayList(),這樣將來代碼無論改成List v = n
47、ew LinkedList()還是List v = new Vector(),其余代碼都不受影響。(6) 匿名類轉(zhuǎn)換為內(nèi)部類(Anonymous class to Inner Class):匿名類轉(zhuǎn)換成內(nèi)部類,內(nèi)部類轉(zhuǎn)換成外部類,從而提高可重用性。,,(7) 還原方法:是抽取方法(Extract Method)的逆過程。使用“方法調(diào)用”可以改善程序結(jié)構(gòu),但是這樣勢必要增加調(diào)用開銷。若某些方法只有一個(gè)調(diào)用者,就可以把該方法的代碼放入調(diào)用者,以減少調(diào)用開銷,改進(jìn)性能。(8) 封裝屬性(Encapsulation attribute):是旨在提高程序封裝性的一種重構(gòu)方法。將屬性定義成私有的,并提供s
48、et/get方法訪問。 (9) 屬性、方法上移或下移(Attribute Move up):將子類中的屬性或者方法上移到父類中,該屬性和方法可為所有子類共享;或者將父類中的屬性和方法下移到子類中,這樣該屬性和方法只能為該子類獨(dú)有。,,(10) 提取父類或者接口(Extract Interface):根據(jù)類中的公有方法,創(chuàng)建父類或者接口,并讓該類繼承所提取的父類,或者實(shí)現(xiàn)提取的接口。此類重構(gòu)方法主要適用于當(dāng)多個(gè)客戶使用同一個(gè)接口的子集(不同的客戶使用不同的接口,以保持安全性),或兩個(gè)類擁有公共父類或公共接口的時(shí)候(兩個(gè)類都繼承同一父類或?qū)崿F(xiàn)同一接口)。例如,下面代碼中的MyClass對外提供了三
49、個(gè)公共操作接口。class MyClass public void f1() public void f2() public void f3(),,假設(shè)客戶A只能訪問f1()方法,客戶B只能訪問f2()方法,客戶C只能訪問f3()方法,則應(yīng)該設(shè)計(jì)成:MyClass實(shí)現(xiàn)三個(gè)接口InterfaceA、InterfaceB、InterfaceC:class MyClass implements InterfaceA,InterfaceB,InterfaceC public void f1() public void f2() public void f3()interface Interface A
50、 public void f1();Interface Interface B Public void f2();,,在客戶A的訪問代碼中,這樣聲明引用變量,可以保證客戶A只能訪問f1()方法。InterfaceA aobj = new My Class();aobj.f1();在客戶B的訪問代碼中,這樣聲明引用變量,可以保證客戶B只能訪問f2()方法。InterfaceB bobj = new MyClass();bobj.f2();,,(11) 創(chuàng)建代理(Proxy):創(chuàng)建多個(gè)方法的代理類。具體地說,這種重構(gòu)要創(chuàng)建一個(gè)類(代理類),該類引用被代理的類實(shí)例,提供選定的方法接口。通過調(diào)用被代理
51、類的方法即可實(shí)現(xiàn)該方法。這種重構(gòu)適合于將一個(gè)類的某些方法公開給某些客戶,或者用以增加新的方法。創(chuàng)建代理可以實(shí)現(xiàn)多種設(shè)計(jì)模式,如包裝(wrapper)、修飾(decorator)、適配器(adapter)等。,,(12) 對象工廠方法(Object Factory Method):這種重構(gòu)將會自動定義創(chuàng)建對象實(shí)例的工廠方法。這種代碼的優(yōu)勢是可以把創(chuàng)建對象實(shí)例的過程標(biāo)準(zhǔn)化、工業(yè)化,從而為對象容器和框架提供基礎(chǔ)。例如,Spring框架就可以根據(jù)在配置文件中定義的類自動實(shí)例化對象,支持實(shí)現(xiàn)在程序代碼之外替換類的功能。除了上述的重構(gòu)方法外,諸如把順序結(jié)構(gòu)的代碼修改成選擇結(jié)構(gòu)或者重復(fù)結(jié)構(gòu)、將離散的數(shù)據(jù)結(jié)構(gòu)
52、轉(zhuǎn)換為整體的集合變量等也屬于代碼重構(gòu)的范疇。經(jīng)過合理重構(gòu)的代碼結(jié)構(gòu)會更加穩(wěn)定,重用程度會更高,也更容易維護(hù)和改進(jìn)。從開發(fā)者的角度來看,無經(jīng)驗(yàn)的開發(fā)人員需要重構(gòu)的次數(shù)明顯要比有經(jīng)驗(yàn)的開發(fā)人員多,所以掌握重構(gòu)技術(shù)也是由初學(xué)者進(jìn)化到專家的必由之路。,,7.5.3 一個(gè)程序結(jié)構(gòu)改進(jìn)(重構(gòu))的例子本節(jié)通過計(jì)算多個(gè)圖形面積之和的例子來說明程序結(jié)構(gòu)的改進(jìn)過程和面向?qū)ο蠹夹g(shù)應(yīng)用的關(guān)系,也具體地說明重構(gòu)技術(shù)的應(yīng)用方法。問題:計(jì)算幾種圖形的面積之和。例如:圓、矩形、三角形等。初始的程序代碼如下:,,double s1 = 50 * 50 * 3.1416; //半徑為50的圓double s2 = 20 * 30
53、; //長、寬為20、30的矩形double s3 = 0.5 * 10 * 20; //底邊為10,高為20的三角形double sum = s1 + s2 + s3;//求和 如果要把該段代碼重用于其他計(jì)算面積之和的程序中,則幾乎沒有任何可重用的地方。,,第一次改進(jìn),數(shù)據(jù)結(jié)構(gòu)+控制結(jié)構(gòu):使用數(shù)組表示多個(gè)圖形面積,然后利用循環(huán)計(jì)算其面積之和。double s = new double3;s0 = 50 * 50 * 3.1416;s1 = 20 * 30;s2 = 0.5 * 10 * 20;double sum = 0.0;for (int i=0;i 54、m += si;,,在這次改進(jìn)中,有些代碼可以用于其他計(jì)算面積之和甚至更一般的程序中,如計(jì)算多個(gè)實(shí)數(shù)之和的程序中。但這種重用只是通過復(fù)制代碼來實(shí)現(xiàn)的。第二次改進(jìn):提取方法,引入變量、參數(shù)等。例如:計(jì)算圓面積、三角形面積、矩形面積,計(jì)算面積之和的方法等。根據(jù)簡單的幾何公式,對于計(jì)算圓、矩形、三角形面積及計(jì)算多個(gè)實(shí)數(shù)和的方法分別定義如下:,,double circleArea( double r) // 計(jì)算半徑為r的圓面積的方法double rectArea(double a, double b) // 計(jì)算長、寬分別為a、b的矩形面積的方法double triangleArea(double 55、s, double h) // 計(jì)算底邊為s、高為h的三角形面積的方法double tota(Area(double s),,如果給定參數(shù)的具體值,調(diào)用這些方法就可以計(jì)算出具體的圓、矩形、三角形的面積并求其面積和。例如:s0 = circleArea(50); // 計(jì)算半徑是50的圓面積s1 = triangleArea(10,5); // 計(jì)算底是10,高是5的三角形面積s2 = rectAtrea(10,20); // 計(jì)算寬是10,高是20的矩形面積sum = totalArea(s);現(xiàn)在程序中定義的方法可以用于計(jì)算多個(gè)圓、多個(gè)矩形、多個(gè)三角形的面積,以及任意多個(gè)面積的和。,,試想一 56、下,對于計(jì)算三角形面積,還可以已知三角形三邊、兩邊夾角、三角形三個(gè)頂點(diǎn)等條件,這樣就會增加如下方法:triangleArea(double s1, double s2, double s3)triangleArea(double s1, double s2 , double alfa);triangleArea(double x1,double y1, double x2,double y2, double x3,double y3),,,對于其他圖形也有類似情形,這樣計(jì)算面積的方法數(shù)目也會很快地增長。為了更好地分類這種方法,現(xiàn)在可以引入類,以完成第三次改進(jìn),將計(jì)算三角形面積的三個(gè)方法封裝在三 57、角形類中,但此時(shí)方法是靜態(tài)的,也就是說僅僅是命名空間的包裝,此時(shí)并不包含數(shù)據(jù),如圖形尺寸的封裝。圖形尺寸是通過三角形方法的參數(shù)傳遞進(jìn)去的,此時(shí)的方法也可以看成是一些公共的實(shí)用方法。,,class Triangle public static area(double w, double h) public static area(double s1, double s2, double s3) ,,,這次改進(jìn)的結(jié)果和上次改進(jìn)的結(jié)果沒有本質(zhì)上的改變,都是結(jié)構(gòu)化的改進(jìn),也就是程序的結(jié)構(gòu)是由方法的定義和調(diào)用組成的。第四次改進(jìn):封裝對象。對于上面封裝的三角形類來說,只包含一些實(shí)用方法,并沒有共享三角形的 58、數(shù)據(jù)。實(shí)際上作為一個(gè)三角形對象,其狀態(tài)或者數(shù)據(jù)是唯一的,所有的方法只是返回其狀態(tài)或者對外提供服務(wù)的。只有定義了數(shù)據(jù)及對該數(shù)據(jù)的操作的對象整體,才能更好地反映客觀現(xiàn)實(shí),如下面代碼:,,class Triangle double width, height; public double area() ,,此時(shí)的類也可以看成是一種自定義數(shù)據(jù)類型,定義了一組數(shù)據(jù)及其操作。該類可以派生無數(shù)的對象實(shí)例,就像使用數(shù)據(jù)類型可以定義很多變量一樣,可以用作定義變量或者分配空間的模板。,類的引入正像數(shù)據(jù)類型的引入,可以增強(qiáng)程序的安全性,只有同種類型的變量才可以在一起運(yùn)算。以totalArea(double s)為 59、例,該方法本意是計(jì)算多個(gè)圖形面積和,但實(shí)際上只要傳遞進(jìn)來的是實(shí)數(shù),都可以計(jì)算,甚至負(fù)數(shù)。這是因?yàn)榉椒▍?shù)是實(shí)型,如果該參數(shù)定義為totalArea(Triangle shapes),則該方法只能接收Triangle類型的值,這樣就避免了因?yàn)殄e(cuò)傳了其他類型或者其他意義的參數(shù)而產(chǎn)生錯(cuò)誤。但是這樣一來,針對每種圖形類型都需要定義一個(gè)計(jì)算面積和的方法。這是由于類型個(gè)性化所帶來的問題,增加了語法的嚴(yán)格性和程序安全性,但是降低了效率??梢酝ㄟ^定義每種具體圖形類的父類來提取其共性,提高代碼效率。,,第五次改進(jìn):引入父類和繼承機(jī)制。public Triangle extends Shape public do 60、uble area()return 0.0;這樣計(jì)算多個(gè)圖形面積和的方法就可以定義成如下形式:public double totalArea(Shape s) double sum = 0.0;for(int i=0;i 61、形)中。第六次改進(jìn):將父類定義成抽象類或者接口。abstract class Shape abstract double area();,,在第五次改進(jìn)中引入的父類提高了類型的效率,但是也帶來了一個(gè)問題,那就是父類的方法實(shí)現(xiàn)問題。父類Shape是一般的圖形類,是一個(gè)抽象概念,其計(jì)算面積的方法肯定是不存在的或者沒辦法實(shí)現(xiàn)的,在上面代碼中令其返回0,實(shí)際上是假設(shè)或者權(quán)宜之計(jì),因?yàn)樵诔绦蛑袑?shí)際上是沒法調(diào)用該方法的,因此其實(shí)現(xiàn)方法也沒有什么意義。因此將其定義成抽象類更合適,這樣計(jì)算面積的方法就可以定義為抽象的,只給出接口而不給出實(shí)現(xiàn)。這時(shí)候父類就純粹變成一種類型了,失去了對象的含義。這種方法可以防止 62、誤用父類,因?yàn)槌橄箢惒豢梢詣?chuàng)建實(shí)例;也可以統(tǒng)一子類接口,子類必須要實(shí)現(xiàn)父類的抽象操作,還可以延遲實(shí)現(xiàn),即把操作的實(shí)現(xiàn)延遲到子類中去,從而建立更抽象、更通用的程序。,,接口的含義和抽象類類似,其所有的操作都是抽象的。接口是用來抽象幾乎沒有相似性的對象的公共操作機(jī)制的。在上述例子中,抽象類是可以利用接口來代替的,表示了計(jì)算面積這樣的操作接口。interface CanCalculateArea public double area();,,改成接口實(shí)現(xiàn)后,可以計(jì)算面積的對象就不止上面的圓、矩形、三角形等圖形,還可以包括長方體、圓柱、錐,甚至實(shí)物,如汽車、廠房、零件等。上述程序的主要演化過程用圖表示 63、為如圖7.15所示。從圖7.15中的進(jìn)化過程可以看出,程序從簡單的變量計(jì)算結(jié)構(gòu)最終進(jìn)化到具有繼承關(guān)系的復(fù)雜類結(jié)構(gòu),程序功能也從只能計(jì)算確定的簡單圖形面積之和,進(jìn)化到可以計(jì)算任意多個(gè)任意圖形的面積之和。這實(shí)際上是一段抽象的程序代碼,其模式可以應(yīng)用于很多情況,例如繪制多個(gè)圖形、通知所有視圖對象、讓多個(gè)對象都執(zhí)行同名操作等。這段程序代碼的功能就在于遍歷對象集合,執(zhí)行每個(gè)對象的同名操作,代碼模板如下:for(Object o: objSet) o.operate (),,由于對象的繼承性和多態(tài)性,集合中的對象可以是任意的,只要繼承自同一個(gè)父類即可。每種對象的同名操作operate的實(shí)現(xiàn)是不一樣的。代碼 64、即體現(xiàn)了對不同對象操作的共性(如計(jì)算面積),又通過子類和多態(tài)體現(xiàn)了每種對象的個(gè)性(每種圖形的面積公式是不一樣的)。這段代碼簡潔高效,即保證了安全性,又保證了可擴(kuò)充性和可維護(hù)性,也代表了一種模式(pattern)。從程序結(jié)構(gòu)的角度來看,模式就代表了一種可以解決很多類似問題的抽象程序解決方案,這種抽象的解決方案往往給出的只是程序結(jié)構(gòu)的設(shè)計(jì)方案,關(guān)于模式在7.7節(jié)中有較詳細(xì)的說明。,,圖7.15 程序結(jié)構(gòu)的演化過程,,7.6 面向?qū)ο筌浖こ?.6.1 傳統(tǒng)的面向?qū)ο筌浖こ虃鹘y(tǒng)的面向?qū)ο筌浖こ淌菍⒔Y(jié)構(gòu)化的軟件工程生命周期、管理方法和面向?qū)ο蠹夹g(shù)結(jié)合的一種軟件工程方法。它將面向?qū)ο筌浖_發(fā)過程分成 65、面向?qū)ο笙到y(tǒng)分析、面向?qū)ο笙到y(tǒng)設(shè)計(jì)、面向?qū)ο笙到y(tǒng)實(shí)現(xiàn)、面向?qū)ο笙到y(tǒng)測試等階段,其核心技術(shù)是面向?qū)ο蠼:兔嫦驅(qū)ο蟪绦蛟O(shè)計(jì)。,,在面向?qū)ο蠼V幸话阋⑷N模型:對象模型、動態(tài)模型和功能模型。對象模型描述系統(tǒng)中的類及其關(guān)系,屬于系統(tǒng)的靜態(tài)結(jié)構(gòu);動態(tài)模型描述在系統(tǒng)功能的實(shí)現(xiàn)過程中系統(tǒng)對象之間的交互過程;功能模型類似于系統(tǒng)的高層數(shù)據(jù)流圖,抽象了系統(tǒng)的主要功能。在傳統(tǒng)的面向?qū)ο筌浖こ痰姆治龊驮O(shè)計(jì)階段,都需要建立這三種模型,只不過涉及的對象范圍、抽象的層次、描述的粒度和細(xì)度等有所不同。,,在系統(tǒng)分析期間比較關(guān)注現(xiàn)實(shí)世界的建模。此時(shí),建立起來的對象模型是業(yè)務(wù)模型或稱概念模型。它是對現(xiàn)實(shí)世界事物及其關(guān)系 66、的直接反映,較少涉及系統(tǒng)實(shí)現(xiàn)方法和系統(tǒng)對象的描述(分析階段涉及到的系統(tǒng)對象多是抽象的,如界面對象等)。在此階段的對象一般稱為業(yè)務(wù)對象或者分析對象。此時(shí)建立的動態(tài)模型也是針對在業(yè)務(wù)功能的實(shí)現(xiàn)過程中,業(yè)務(wù)對象之間交互過程的描述。功能模型則從系統(tǒng)外部或比較高的層次上去抽取系統(tǒng)的功能。,,系統(tǒng)設(shè)計(jì)階段則要考慮系統(tǒng)的實(shí)現(xiàn)方案,比如說確定系統(tǒng)運(yùn)行模式、考慮系統(tǒng)軟件分層架構(gòu)等,要考慮系統(tǒng)的界面、控制等因素。分析階段建立的各種模型作為設(shè)計(jì)階段的輸入,在設(shè)計(jì)階段中對前期工作進(jìn)行系統(tǒng)化的包裝,使其更適合于信息系統(tǒng)中的實(shí)現(xiàn)。例如給業(yè)務(wù)對象包裝上界面類,將其放在某個(gè)系統(tǒng)架構(gòu)(如基于組件的架構(gòu))下進(jìn)行物理設(shè)計(jì)等。即使是原來的概念對象模型(業(yè)務(wù)模型),也需要進(jìn)一步的綜合、優(yōu)化、分離、抽象(如使用分析模式和設(shè)計(jì)模式等),以適合于系統(tǒng)的目標(biāo)和信息系統(tǒng)的特點(diǎn),滿足系統(tǒng)的穩(wěn)定性、維護(hù)性、重用性、移植性、分布性等要求。設(shè)計(jì)階段的動態(tài)模型則是針對在系統(tǒng)功能執(zhí)行過程中所有系統(tǒng)對象的交互過程進(jìn)行建模。功能模型則應(yīng)該進(jìn)一步細(xì)化成整個(gè)系統(tǒng)的功能而不僅僅是業(yè)務(wù)功能。,,可以這樣說,分析的任務(wù)是將現(xiàn)實(shí)世界中或者問題域中的概念抽象出來,提
- 溫馨提示:
1: 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
2: 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
3.本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
5. 裝配圖網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 建筑施工重大危險(xiǎn)源安全管理制度
- 安全培訓(xùn)資料:典型建筑火災(zāi)的防治基本原則與救援技術(shù)
- 企業(yè)雙重預(yù)防體系應(yīng)知應(yīng)會知識問答
- 8 各種煤礦安全考試試題
- 9 危險(xiǎn)化學(xué)品經(jīng)營單位安全生產(chǎn)管理人員模擬考試題庫試卷附答案
- 加壓過濾機(jī)司機(jī)技術(shù)操作規(guī)程
- 樹脂砂混砂工藝知識總結(jié)
- XXXXX現(xiàn)場安全應(yīng)急處置預(yù)案
- 某公司消防安全檢查制度總結(jié)
- 1 煤礦安全檢查工(中級)職業(yè)技能理論知識考核試題含答案
- 4.燃?xì)獍踩a(chǎn)企業(yè)主要負(fù)責(zé)人模擬考試題庫試卷含答案
- 工段(班組)級安全檢查表
- D 氯化工藝作業(yè)模擬考試題庫試卷含答案-4
- 建筑起重司索信號工安全操作要點(diǎn)
- 實(shí)驗(yàn)室計(jì)量常見的30個(gè)問問答題含解析