趙 焱
(昆明船舶設(shè)備研究試驗(yàn)中心人事處,云南昆明 650000)
為提高軟件的開(kāi)發(fā)效率,軟件工程師們?cè)絹?lái)越追求開(kāi)發(fā)更多、更有通用性的可重用構(gòu)件。傳統(tǒng)的結(jié)構(gòu)化方法是將系統(tǒng)功能分解編寫(xiě)模塊,每個(gè)模塊實(shí)現(xiàn)特定的功能,可重用的單位只能是模塊,且用戶(hù)需求的變化需花費(fèi)較大代價(jià)去實(shí)現(xiàn)。為了適應(yīng)軟件開(kāi)發(fā)的更高要求,提高軟件產(chǎn)品的穩(wěn)定性和可修改性,從而產(chǎn)生了面向?qū)ο螅?]。
面向?qū)ο?Object Oriented,OO)是一種軟件開(kāi)發(fā)的方法。起初,其專(zhuān)指在程序設(shè)計(jì)中采用封裝、繼承和多態(tài)等設(shè)計(jì)方法。但如今,面向?qū)ο箝_(kāi)發(fā)方法的研究已日趨成熟,面向?qū)ο蟮乃枷胍焉婕暗杰浖_(kāi)發(fā)的各個(gè)方面。
面向?qū)ο蟮能浖_(kāi)發(fā)包括3個(gè)階段:面向?qū)ο蟮姆治?Object Oriented Analysis,OOA),面向?qū)ο蟮脑O(shè)計(jì)(Object Oriented Design,OOD)、以及面向?qū)ο蟮膶?shí)現(xiàn)(Object Oriented Programming,OOP)。面向?qū)ο蠓治龅哪康氖菍?duì)客觀(guān)世界的系統(tǒng)進(jìn)行建模,用分析模型來(lái)明確問(wèn)題需求,為用戶(hù)和開(kāi)發(fā)人員提供一個(gè)協(xié)商的基礎(chǔ),同時(shí)為面向?qū)ο笤O(shè)計(jì)和實(shí)現(xiàn)提供了一個(gè)基本框架。面向?qū)ο蟮脑O(shè)計(jì)以面向?qū)ο蟮姆治鰹榛A(chǔ),通過(guò)系統(tǒng)設(shè)計(jì)和對(duì)象設(shè)計(jì)將分析階段得到的需求轉(zhuǎn)變成符合成本和質(zhì)量要求的、抽象的系統(tǒng)實(shí)現(xiàn)方案。面向?qū)ο蟮膶?shí)現(xiàn)即選用能最完善、準(zhǔn)確地表達(dá)問(wèn)題域語(yǔ)義的面向?qū)ο笳Z(yǔ)言開(kāi)發(fā)軟件,其基本目的和主要優(yōu)點(diǎn)是通過(guò)重用提高軟件的生產(chǎn)率[1]。
在面向?qū)ο蟮能浖_(kāi)發(fā)過(guò)程中,一般通過(guò)對(duì)接口編程、改寫(xiě)類(lèi)的實(shí)例方法和代碼分離的方式來(lái)實(shí)現(xiàn)代碼重用。
面向接口編程是實(shí)際開(kāi)發(fā)過(guò)程中實(shí)現(xiàn)代碼重用的一個(gè)重要方法,其根本思想是將一個(gè)接口或抽象類(lèi)從一組功能相同的組件中進(jìn)行抽象形成。通過(guò)面向接口編程,當(dāng)任務(wù)中需要其他組件時(shí),無(wú)需對(duì)程序代碼進(jìn)行更改,而只需更改該接口的實(shí)現(xiàn)即可?,F(xiàn)存的組件不能滿(mǎn)足設(shè)計(jì)需求時(shí),通常有兩種方法來(lái)完成:一是創(chuàng)建一組新的組件;二是對(duì)現(xiàn)存的相關(guān)組件進(jìn)行擴(kuò)展,通過(guò)新的子類(lèi)來(lái)完成所需的擴(kuò)展功能[2]。
繼承是代碼重用的一個(gè)基本方法,但在面向?qū)ο缶幊讨?,?lèi)繼承不是代碼重用的真正要點(diǎn),可通過(guò)對(duì)接口編程來(lái)達(dá)到代碼重用的目的[3]。在實(shí)際應(yīng)用過(guò)程中,當(dāng)某塊代碼能編寫(xiě)成獨(dú)立的全局過(guò)程時(shí),只要將其所有類(lèi)形式的參數(shù)改為接口的形式,就可進(jìn)一步提高的可重用能力。經(jīng)此改動(dòng)后,過(guò)程的參數(shù)就不僅是原來(lái)類(lèi)所創(chuàng)建的對(duì)象,而是實(shí)現(xiàn)了該接口所有類(lèi)的對(duì)象。例如,假設(shè)有這樣一個(gè)全局靜態(tài)方法contains():
static public bollean contains(Rectangle rect,int x,int y){…}
該方法用于檢查指定的點(diǎn)是否包含在矩形內(nèi),若將rect的參數(shù)類(lèi)型Rectangle改成接口:
static public oolean contains(Rectangular rect,int x,int y){…}
其中,Rectangular接口的定義如下
public interface Rectangular{Rectangle getBounds();}
經(jīng)此改動(dòng)后,contains方法的參數(shù)變成所有實(shí)現(xiàn)了Rectangular接口類(lèi)的對(duì)象。通過(guò)將參數(shù)類(lèi)型改為接口的形式,可放寬對(duì)參數(shù)類(lèi)型的限制,擴(kuò)大過(guò)程所使用參數(shù)的范圍,從而大幅提高方法的可重用能力。
通過(guò)上述分析可知,將參數(shù)類(lèi)型改為接口可提高代碼的可重用能力,但在實(shí)際應(yīng)用過(guò)程中,將參數(shù)類(lèi)型改成接口可能有多種方式,不同的更改方式其實(shí)現(xiàn)所需的代碼、數(shù)據(jù)和容易程度均不相同。因此,首先需確保方法對(duì)參數(shù)的要求,然后盡量將參數(shù)類(lèi)型改為簡(jiǎn)單的接口。接口越簡(jiǎn)單,類(lèi)實(shí)現(xiàn)接口時(shí)就越容易,能將其作為參數(shù)進(jìn)行使用的類(lèi)也就越多,代碼的可重用能力則越大[4]。
在實(shí)際編程過(guò)程中,對(duì)于那些能執(zhí)行某個(gè)單一任務(wù)的方法,可進(jìn)行重用來(lái)節(jié)省編程的成本。為此,可通過(guò)將相關(guān)的實(shí)例方法組織成為獨(dú)立的類(lèi),使其成為一個(gè)公用的全局性靜態(tài)過(guò)程。為了提高這種過(guò)程的可重用性,過(guò)程代碼應(yīng)同靜態(tài)工具方法編寫(xiě)一致:即只能使用自身的輸入?yún)?shù),僅可調(diào)用其他全局性的過(guò)程,不能使用任何非局部的變量[5]。這種對(duì)外部依賴(lài)關(guān)系的限制簡(jiǎn)化了過(guò)程的應(yīng)用,使得過(guò)程能方便地用于任何地方。這種組織方式的使用使得代碼結(jié)構(gòu)更加清晰。因此,即使不考慮重用性的代碼也能從中獲益。
眾所周知,Java中的方法不能脫離類(lèi)而單獨(dú)存在。所以為實(shí)現(xiàn)代碼重用,可將相關(guān)過(guò)程定義為公用的靜態(tài)方法,并組織為獨(dú)立的類(lèi)。例如,對(duì)于Polygon有:
class Polygon{…
public int getPerimeter(){…}
public boolean isConvex(){…}
public boolean containsPoint(Point p){…}..
}可將其改寫(xiě)為:
public int getPerimeter(){return pPolygon.computePerimeter(this);}
public boolean isConvex(){return pPolygon.isConvex(this);}
public boolean containsPoint(Point p){return pPolygon.containsPoint(this,p);}
其中,pPolygon類(lèi)定義如下:
class pPolygon{
static public int computePerimeter(Polygon polygon){…}
static public boolean isConvex(Polygon polygon){…}
static public boolean containsPoint(Polygon polygon,Point p){…}
}
在上述例子中,pPolygon類(lèi)中封裝的公用靜態(tài)方法參數(shù)均與Polygon類(lèi)型的對(duì)象有關(guān),通過(guò)改寫(xiě)pPolygon類(lèi)的實(shí)例方法,Polygon類(lèi)的功能轉(zhuǎn)由pPolygon類(lèi)以過(guò)程為單位進(jìn)行提供,不繼承Polygon類(lèi)也可使用Polygon類(lèi)的功能。由此,客戶(hù)代碼只使用自身需要的代碼,而無(wú)需關(guān)心其他不需要的功能。
由于繼承會(huì)帶來(lái)一些多余的方法和數(shù)據(jù)成員,且更改父類(lèi)時(shí)會(huì)影響子類(lèi)功能,子類(lèi)對(duì)父類(lèi)的依賴(lài)關(guān)系會(huì)使代碼變得復(fù)雜,子類(lèi)中的覆蓋方法是否要調(diào)用父類(lèi)中的對(duì)應(yīng)方法有時(shí)也并不明顯。因此,僅通過(guò)繼承來(lái)實(shí)現(xiàn)代碼重用會(huì)存在一定的不足,其并不是最為理想的代碼重用機(jī)制,所以通常是將繼承與代碼分離技術(shù)相結(jié)合來(lái)實(shí)現(xiàn)代碼的重用。所謂代碼分離就是將可變部分和不可變部分分離開(kāi),其是面向?qū)ο笤O(shè)計(jì)的一個(gè)重要原則。在通過(guò)繼承進(jìn)行代碼重用時(shí),可在抽象基類(lèi)中定義好不可變的部分,然后由其子類(lèi)去實(shí)現(xiàn)可變的部分[6]。
盡管代碼重用的優(yōu)勢(shì)明顯,但并非所有的代碼均能進(jìn)行代碼重用。代碼重用需注意以下幾點(diǎn):(1)只有高通用性的代碼才可重用。一般來(lái)說(shuō),通用性較低的代碼不適合進(jìn)行代碼重用。因在多個(gè)項(xiàng)目間重用不為通用性設(shè)計(jì)的代碼,反而會(huì)使整個(gè)開(kāi)發(fā)過(guò)程變得復(fù)雜,同時(shí)會(huì)增加開(kāi)發(fā)的時(shí)間和成本。(2)依賴(lài)度高的代碼不適合重用。有些代碼與開(kāi)發(fā)人員有較大的依賴(lài)性,且無(wú)相應(yīng)的文檔來(lái)描述程序設(shè)計(jì)細(xì)節(jié)。新進(jìn)項(xiàng)目的人需花費(fèi)大量的時(shí)間和精力才可理清楚代碼間的相互關(guān)系。類(lèi)似依賴(lài)度高的代碼越多,工作難度越大,進(jìn)行代碼重用就越困難。(3)高成本、低使用率的代碼不適合重用。代碼重用雖有眾多優(yōu)勢(shì),但在使用過(guò)程中仍需考慮其成本和使用率。若需付出過(guò)高的成本,且重用代碼的使用率較低,則不適合進(jìn)行代碼重用。
介紹了面向?qū)ο蟮能浖_(kāi)發(fā)方法及其3個(gè)階段:面向?qū)ο蟮姆治?、面向?qū)ο蟮脑O(shè)計(jì)和面向?qū)ο蟮膶?shí)現(xiàn)。并結(jié)合實(shí)例分析了在該開(kāi)發(fā)方法中代碼重用的3種實(shí)現(xiàn)策略,即對(duì)接口編程、改寫(xiě)類(lèi)的實(shí)例方法和代碼分離。通過(guò)這3種策略與面向?qū)ο缶幊碳夹g(shù)的結(jié)合,能簡(jiǎn)化方法的復(fù)雜性和依賴(lài)關(guān)系,同時(shí)可提高方法的可重用性和內(nèi)聚力。但并非所有的代碼均能進(jìn)行代碼重用。因此,在重用過(guò)程中要注意代碼的通用性和依賴(lài)度,同時(shí)還需考慮重用的成本和重用代碼的使用率,使代碼重用在面向?qū)ο筌浖_(kāi)發(fā)中真正發(fā)揮其的重要作用。
[1]梁燕來(lái),程裕強(qiáng).Java面向?qū)ο蟪绦蛟O(shè)計(jì)[M].北京:人民郵電出版社,2013.
[2]Bruce Eckel.Java編程思想[M].3版.陳昊鵬,譯.北京:機(jī)械工業(yè)出版社,2005.
[3]Allen Holub.Build user interfaces for object- oriented systems[EB/OL].(2000 -03)[2014 -10]http://www.javaworld.com/article/2076459/core-java/building-userinterfaces-for-object-oriented-systems- -part-1.html.
[4]馬永杰,蔣兆遠(yuǎn).基于功能構(gòu)件的軟件復(fù)用方法[J].計(jì)算機(jī)應(yīng)用與軟件,2009,26(8):75 -77.
[5]謝冰,張晨東.面向?qū)ο鬁y(cè)試代碼復(fù)用算法與工具[J].計(jì)算機(jī)工程與科學(xué),2008,30(11):109 -110.
[6]郭志學(xué).易學(xué)設(shè)計(jì)模式[M].北京:人民郵電出版社,2009.
[7]成岳鵬,戴永成.基于面向?qū)ο蟮能浖赜眉夹g(shù)[J].河北工業(yè)科技,2009,26(5):434 -437.
[8]薩默維爾.軟件工程[M].9版.北京:機(jī)械工業(yè)出版社,2011.
[9]Herbert Schildt.Java完全參考手冊(cè)[M].8版.王德才,吳明飛,唐業(yè)軍,譯.北京:清華大學(xué)出版社,2012.
[10]秦小波.設(shè)計(jì)模式之禪[M].2版.北京:機(jī)械工業(yè)出版社,2013.
[11]朱福喜.面向?qū)ο笈cJava程序設(shè)計(jì)[M].北京:清華大學(xué)出版社,2009.
[12]Grady Booch.面向?qū)ο蠓治雠c設(shè)計(jì)[M].3版.北京:電子工業(yè)出版社,2012.