第6章 軟件設(shè)計(jì)目標(biāo)_第1頁
第6章 軟件設(shè)計(jì)目標(biāo)_第2頁
第6章 軟件設(shè)計(jì)目標(biāo)_第3頁
第6章 軟件設(shè)計(jì)目標(biāo)_第4頁
第6章 軟件設(shè)計(jì)目標(biāo)_第5頁
已閱讀5頁,還剩94頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

第6章軟件設(shè)計(jì)目標(biāo)《軟件體系結(jié)構(gòu)與設(shè)計(jì)實(shí)用教程》第二版6.1概述基本概念正確性指設(shè)計(jì)符合需求,代碼按照要求執(zhí)行。通常對給定的需求可能有多種正確的設(shè)計(jì)。如果在出現(xiàn)錯(cuò)誤時(shí)應(yīng)用程序也能執(zhí)行,那么設(shè)計(jì)是具有健壯性的;錯(cuò)誤的種類有很多,用戶在操作應(yīng)用程序時(shí)會(huì)出現(xiàn)一些錯(cuò)誤,軟件開發(fā)者在設(shè)計(jì)和編碼時(shí)也會(huì)犯一些錯(cuò)誤一個(gè)可維護(hù)性的設(shè)計(jì)意味著可以很容易地對其進(jìn)行修改可復(fù)用性是指可以將其方便地移植到其他應(yīng)用中。高效性有兩個(gè)方面——時(shí)間效率和空間效率。實(shí)例與分析用Java實(shí)現(xiàn)一個(gè)計(jì)算器控制臺(tái)程序,輸入兩個(gè)數(shù),相除得到結(jié)果。importjava.io.*;classCommandLineCalculator{publicstaticvoidmain(String[]args)throwsIOException{BufferedReaderb=newBufferedReader(newInputStreamReader(System.in));System.out.println("請輸入數(shù)字A:");

StringA=b.readLine();

//輸入錯(cuò)誤怎么辦?

System.out.println("請輸入數(shù)字B:");

StringB=b.readLine();

intC=(newInteger(A)).intValue()/(newInteger(B)).intValue();

//B=0怎么辦?System.out.println("結(jié)果是:"+C);}}實(shí)例與分析分析一下實(shí)現(xiàn)方法的特點(diǎn)和需要考慮的問題。首先,要求的功能實(shí)現(xiàn)了,所以正確性是滿足的。其次,假如用戶輸入出錯(cuò),系統(tǒng)將崩潰或出現(xiàn)不可預(yù)知的結(jié)果,所以健壯性存在問題。第三,Calculator類是專門為特殊的問題制定的,所以不能作為整體復(fù)用。所以,可復(fù)用性存在問題。第五,要修改Calculator類比較困難。加一個(gè)減法功能,會(huì)發(fā)現(xiàn)增加功能需要修改原來的類,這就違背了開-閉原則。所以可維護(hù)性存在問題。第四,執(zhí)行速度怎樣?需要多少內(nèi)存?這是高效性的問題。應(yīng)用程序要在真實(shí)的計(jì)算機(jī)上運(yùn)行,并且被人們使用。而計(jì)算機(jī)的內(nèi)存是有限的,同時(shí)用戶也不愿意長時(shí)間等待應(yīng)用程序完成操作。本程序較簡單,可不考慮這方面的內(nèi)容。6.2健壯性健壯性如果設(shè)計(jì)或?qū)崿F(xiàn)能處理各種各樣的異常情況,比如數(shù)據(jù)錯(cuò)誤、用戶錯(cuò)誤、環(huán)境條件,那么這個(gè)設(shè)計(jì)是健壯的。為了提高健壯性,需要防止錯(cuò)誤輸入,包括用戶輸入,數(shù)據(jù)通信、其他應(yīng)用程序的方法調(diào)用等非用戶的輸入;還要防止開發(fā)錯(cuò)誤,包括錯(cuò)誤的設(shè)計(jì)和錯(cuò)誤的實(shí)現(xiàn)。上小節(jié)程序的一種執(zhí)行結(jié)果如下:請輸入數(shù)字A:12請輸入數(shù)字B:2結(jié)果是:6B=0時(shí)的執(zhí)行結(jié)果如下,程序出錯(cuò):請輸入數(shù)字A:12請輸入數(shù)字B:0Exceptioninthread"main"java.lang.ArithmeticException:/byzeroatCalculator.main(Calculator.java:9)修改CommandLineCalculator類的代碼,可使其更健壯。(1)除數(shù)不能為0if(intNumberB!=0)intResult=intNumberA/intNumberB;else{System.out.println("除數(shù)不能為0");

System.exit(0);}(2)當(dāng)用戶輸入不合理的整型數(shù)據(jù),甚至不是整型而是字符串型的數(shù)據(jù)時(shí),程序提示用戶再次輸入,程序仍然能夠繼續(xù)執(zhí)行,得到健壯的交互方式。下面的程序具有了一定的健壯性。importjava.io.*;importjava.util.*;classCommandLineCalculator{privateintaccumulatedValue=0;publicCommandLineCalculator(){super();}privatestaticStringgetAnInputFromUser(){ try{ BufferedReaderb=newBufferedReader(newInputStreamReader(System.in)); return(b.readLine());}catch(IOExceptione){System.out.println(e+"Inputtakentobeasingleblank.");return"";}}publicstaticvoidmain(String[]args){System.out.print("請輸入數(shù)字A:");StringA=getAnInputFromUser();System.out.print("請輸入數(shù)字B:");StringB=getAnInputFromUser();intamountAdded=0;while(!A.equals("stop")&!B.equals("stop")){ try{ inta=(newInteger(A)).intValue();//不是整數(shù)時(shí)出錯(cuò)

intb=(newInteger(B)).intValue();//不是整數(shù)時(shí)出錯(cuò)

intc=a/b;//b=0時(shí)出錯(cuò)System.out.println("結(jié)果是:"+c);}catch(Exceptione){//輸入的不是整數(shù)System.out.println("Sorry--incorrectentry:Tryagain.");}

System.out.print("請輸入數(shù)字A:");A=getAnInputFromUser();System.out.print("請輸入數(shù)字B:");B=getAnInputFromUser();}System.out.println("Applicationends.");}}程序執(zhí)行結(jié)果如下:請輸入數(shù)字A:12請輸入數(shù)字B:0Sorry--incorrectentry:Tryagain.請輸入數(shù)字A:12請輸入數(shù)字B:6結(jié)果是:2請輸入數(shù)字A:12請輸入數(shù)字B:stopApplicationends.上面的代碼比較健壯了。如果這個(gè)應(yīng)用程序通過周期性地將數(shù)據(jù)保存到文件以避免應(yīng)用和系統(tǒng)出現(xiàn)錯(cuò)誤,那么程序?qū)?huì)更加健壯。如果以速度為代價(jià),將數(shù)據(jù)發(fā)送到遠(yuǎn)端的存儲(chǔ)器,那么還可以增加健壯性。但是,上述程序只滿足了當(dāng)前的需求,程序不容易維護(hù),不容易擴(kuò)展,更不容易復(fù)用。從而達(dá)不到高質(zhì)量代碼的要求。6.3高效性高效性高效性(效率問題)的目標(biāo)是利用可用的內(nèi)存,盡可能快地完成工作。利用可用的機(jī)器時(shí)間周期和內(nèi)存,應(yīng)用程序必須在指定的時(shí)間內(nèi)完成特定的功能。同樣,對內(nèi)存容量(RAM或硬盤空間)也有一定的要求。執(zhí)行效率應(yīng)用程序必須在指定的時(shí)間內(nèi)完成特定的功能。航天控制系統(tǒng)等實(shí)時(shí)系統(tǒng)對執(zhí)行速度要求最高,它要求在微秒級(jí)甚至更短的固定時(shí)間內(nèi)完成所需的功能。對于非實(shí)時(shí)系統(tǒng),執(zhí)行速度也很重要。無論設(shè)計(jì)多么出色的應(yīng)用程序,如果不能及時(shí)完成操作,用戶會(huì)很快失去耐心。例如,如果網(wǎng)頁打開過慢,那么等其完全打開時(shí),用戶早就不再關(guān)注它了??梢詮倪h(yuǎn)程調(diào)用、循環(huán)、函數(shù)調(diào)用、對象創(chuàng)建等方面提高執(zhí)行效率。(1)處理循環(huán)問題很多算法分析(例如排序算法分析)就是計(jì)算相關(guān)的平均時(shí)間或最差情況下的時(shí)間。嵌套循環(huán)常常是算法分析的重點(diǎn)。如果外部循環(huán)執(zhí)行10000次,而且內(nèi)部還含有執(zhí)行10000次的循環(huán),那么整個(gè)內(nèi)部操作完成了難以置信的十億次(為兩者乘積)循環(huán)。(2)消除遠(yuǎn)程調(diào)用一個(gè)通過本地網(wǎng)絡(luò)或Internet進(jìn)行的遠(yuǎn)程調(diào)用肯定會(huì)消耗大量的時(shí)間。遠(yuǎn)程調(diào)用操作花費(fèi)的時(shí)間與下面因素有關(guān)網(wǎng)絡(luò)的性能調(diào)用的頻率每次調(diào)用取回的信息量(數(shù)據(jù)量)避免BobSchudy曾經(jīng)指出,可以在后臺(tái)運(yùn)行一個(gè)線程來獲取數(shù)據(jù)。這基于在進(jìn)行操作時(shí)只有一部分的CPU被占用,因而可利用空閑的時(shí)鐘周期來對數(shù)據(jù)進(jìn)行預(yù)取。即使一些數(shù)據(jù)不會(huì)使用,這種預(yù)取處理也將進(jìn)行。Proxy(代理)設(shè)計(jì)模式可以避免不必要的函數(shù)調(diào)用,常用于連接對遠(yuǎn)程函數(shù)的調(diào)用(3)消除或制定函數(shù)調(diào)用函數(shù)調(diào)用的好處很大,但降低了時(shí)間效率,特別是在循環(huán)語句中對函數(shù)進(jìn)行調(diào)用。例如,如下循環(huán):

for(i=0;i<1000;++i)doFunctionCall(i);看上去沒問題,但它掩飾了可能隱含的內(nèi)部循環(huán)(會(huì)對效率產(chǎn)生影響),這完全依靠doFunctionCall()是如何實(shí)現(xiàn)的。消除函數(shù)調(diào)用會(huì)提高代碼效率但降低了可讀性。因?yàn)闇p少函數(shù)調(diào)用,會(huì)產(chǎn)生大量的方法和類,難于擴(kuò)展和復(fù)用。存儲(chǔ)效率應(yīng)用程序需要存儲(chǔ)數(shù)據(jù),以備將來在執(zhí)行時(shí)提取。這需要對存儲(chǔ)數(shù)據(jù)的空間進(jìn)行有效的利用。至少有三種存儲(chǔ)問題:RAM的大小(運(yùn)行時(shí))、代碼本身規(guī)模和輔助存儲(chǔ)器(通常指磁盤驅(qū)動(dòng))的大小。數(shù)據(jù)存儲(chǔ)方面的技術(shù)(獲得存儲(chǔ)效率)。(1)只存儲(chǔ)需要的數(shù)據(jù)(在存儲(chǔ)效率與數(shù)據(jù)提取及重整時(shí)間之間獲得折中);(2)壓縮數(shù)據(jù)(在存儲(chǔ)效率與數(shù)據(jù)壓縮及解壓縮時(shí)間之間獲得折中);(3)按相關(guān)訪問頻率存儲(chǔ)數(shù)據(jù)(在存儲(chǔ)效率與決定存儲(chǔ)位置的時(shí)間之間獲得折中)設(shè)計(jì)效率從簡易性方面的考慮,使用便捷的工具和語言會(huì)節(jié)約大量的設(shè)計(jì)時(shí)間,但程序員也失去了對這種系統(tǒng)使用的時(shí)空方面的控制。例如,為了方便程序員,數(shù)據(jù)庫管理系統(tǒng)提供了大量的內(nèi)置功能。但在早期軍事計(jì)算中,數(shù)據(jù)庫管理系統(tǒng)很少使用,原因就是缺少對時(shí)空效率方面的控制。隨著數(shù)據(jù)庫管理系統(tǒng)的發(fā)展,這種情況發(fā)生了改變,允許使用更多已有的工具。如果考慮源代碼的大小方面的因素,在降低開發(fā)、維護(hù)的成本的同時(shí)也會(huì)犧牲時(shí)空效率。高效性高效性有時(shí)和其他目標(biāo)相矛盾,要考慮可維護(hù)性、可復(fù)用性、健壯性和正確性對高效性的影響。下面總結(jié)了兩個(gè)有效設(shè)計(jì)的基本方法(針對時(shí)間效率的基本方法)。先按其他原則設(shè)計(jì),以可維護(hù)性、可復(fù)用性等原則進(jìn)行設(shè)計(jì),再考慮效率問題,找出效率低的部分,有針對性地修改。一開始就按效率原則進(jìn)行設(shè)計(jì)。確認(rèn)當(dāng)前關(guān)鍵的效率需求,在整個(gè)階段都按需求進(jìn)行設(shè)計(jì)還可以是以上兩種方法的結(jié)合,在整個(gè)過程中都綜合考慮高效性和其他目標(biāo),必要時(shí)折中考慮。6.4可復(fù)用性

基本概念一個(gè)好的設(shè)計(jì)應(yīng)該易于修改和復(fù)用,這就需要考慮可維護(hù)性和復(fù)用性,本小節(jié)討論復(fù)用性,下小節(jié)討論可維護(hù)性。復(fù)用(或者叫重用,Reuse)一個(gè)軟件的組成部分,可以在同一個(gè)項(xiàng)目的不同地方甚至另一個(gè)項(xiàng)目中重復(fù)使用。一種降低成本、獲得最大生產(chǎn)率的方法是利用原有的工作,也就是復(fù)用。JavaAPI的應(yīng)用就是復(fù)用的一個(gè)典型例子,JavaAPI就是可復(fù)用的類集合。復(fù)用的實(shí)現(xiàn)多個(gè)方面實(shí)現(xiàn)復(fù)用代碼類相關(guān)類的聚合(例如:java.awt包)類聚合模式——設(shè)計(jì)模式組件框架軟件體系結(jié)構(gòu)…類的復(fù)用對于一個(gè)已經(jīng)設(shè)計(jì)好的類,可以使用繼承、聚合、依賴等技術(shù)實(shí)現(xiàn)復(fù)用。具體說,將新創(chuàng)建類直接說明為已經(jīng)設(shè)計(jì)好的類(父類)的子類,通過繼承和修改父類的屬性與行為完成新創(chuàng)建類的定義;或者,在新創(chuàng)建類中引進(jìn)已經(jīng)設(shè)計(jì)好的類的對象作為新創(chuàng)建類的成員變量,然后在新創(chuàng)建類中通過成員變量復(fù)用已經(jīng)設(shè)計(jì)好的類的屬性和方法;或者,在新創(chuàng)建類中引進(jìn)已經(jīng)設(shè)計(jì)好的類的對象,作為新創(chuàng)建類中的方法的參數(shù)或返回類型。原始類已經(jīng)設(shè)計(jì)好的類——原始的Customer類。classCustomer{Customer(){}

intCompute(){inti=0;//……returni;}//……}利用繼承實(shí)現(xiàn)復(fù)用classSubCustomerextendsCustomer{SubCustomer(){}intComputeSub(){intbaseAmount;//……baseAmount=Compute(); //調(diào)用父類方法實(shí)現(xiàn)復(fù)用returnbaseAmount;}//……}利用聚合實(shí)現(xiàn)復(fù)用classObjCustomer{Customercustomer=newCustomer();//創(chuàng)建Customer類的對象作為類的成員變量//……ObjCustomer(){}intComputeObj(){//使用Customer類的對象實(shí)現(xiàn)復(fù)用intamount=customer.Compute();//……return0;}}利用依賴實(shí)現(xiàn)復(fù)用(一)classCustomerOper{

//……booleaninsert(Customercustomer){

//使用Customer類的對象作為成員方法的參數(shù)intamount=customer.Compute();//使用Customer類的對象實(shí)現(xiàn)復(fù)用

//……returntrue;

}

//……}

利用依賴實(shí)現(xiàn)復(fù)用(二)classCreateCustomer{

//……CustomerloadCustomer(){

Customercustomer=newCustomer();//創(chuàng)建Customer類的對象//……returncustomer;

//返回Customer類的對象}

//……}可以通過減少類的耦合來增加復(fù)用性。如果類A與類B耦合,沒有類B就不可以使用類A,這降低了類A的復(fù)用性。使用中介者(Mediator)設(shè)計(jì)模式會(huì)減少這種耦合。6.5可維護(hù)性基本概念軟件工程領(lǐng)域最大的挑戰(zhàn)之一就是當(dāng)應(yīng)用程序已經(jīng)做完的時(shí)候需求又改變了;當(dāng)已經(jīng)決定如何去做的時(shí)候,應(yīng)用程序的目標(biāo)卻變化了。無論如何完善軟件需求分析,需求仍然會(huì)在項(xiàng)目開發(fā)過程中發(fā)生變化。設(shè)計(jì)開始后最好能阻止客戶改變需求,但這常常又不太可能。所以,軟件設(shè)計(jì)要具有可維護(hù)性,在設(shè)計(jì)中通常要考慮到將來的變化。1.基于面向?qū)ο蠹夹g(shù)的計(jì)算器程序業(yè)務(wù)邏輯與界面邏輯分開對于前面的計(jì)算器的例子,如果分一個(gè)類出來,讓計(jì)算和顯示分開,也就是讓業(yè)務(wù)邏輯與界面邏輯分開,這樣它們之間的耦合度就下降了,容易維護(hù)或擴(kuò)展。classOperation{//Operation運(yùn)算類

publicintgetResult(intnumberA,intnumberB){intresult=0;if(numberB!=0)result=numberA/numberB;returnresult;}}客戶端代碼如下。importjava.io.*;classclient{publicstaticvoidmain(String[]args){intintNumberA=0,intNumberB=0;try{BufferedReaderbufR=newBufferedReader(newInputStreamReader(System.in));System.out.print("請輸入數(shù)字A:");try{intNumberA=newInteger(bufR.readLine()).intValue();}catch(Exceptione){ System.out.println(e); System.exit(0); }System.out.print("請輸入數(shù)字B:");try{intNumberB=newInteger(bufR.readLine()).intValue();}catch(Exceptione){

System.out.println(e); System.exit(0);

}intintResult=0;intResult=newOperation().getResult(intNumberA,intNumberB);System.out.println("結(jié)果是:"+intResult);}catch(Exceptione){System.out.println(e);}}}程序執(zhí)行結(jié)果為:請輸入數(shù)字A:12請輸入數(shù)字B:6結(jié)果是:2面向?qū)ο笕筇匦允欠庋b、繼承和多態(tài),這里用到的是封裝。優(yōu)點(diǎn)上面的代碼就完全把業(yè)務(wù)和界面分離了。如果要修改界面那就去改界面程序,與運(yùn)算無關(guān)?,F(xiàn)在要寫一個(gè)Windows界面的計(jì)算器應(yīng)用程序,就可以復(fù)用這個(gè)Operation運(yùn)算類了。Web版程序需要也可以用它,PDA、手機(jī)等移動(dòng)系統(tǒng)的軟件也可以用它。缺點(diǎn)如果希望增加加法運(yùn)算,只能改Operation類。加一個(gè)加法運(yùn)算,已經(jīng)寫好的除法運(yùn)算也得來參與編譯,很難避免不小心把除法運(yùn)算改成了減法。本來是加一個(gè)功能,卻使得原有的運(yùn)行良好的功能代碼產(chǎn)生了變化。應(yīng)該把加減乘除等運(yùn)算分離,修改其中一個(gè)不影響另外的幾個(gè),增加運(yùn)算算法也不影響其他代碼。這就要用到繼承和多態(tài)。2.基于簡單工廠模式的計(jì)算器程序?qū)τ谇懊娴挠?jì)算器程序,為滿足可維護(hù)性,考慮重構(gòu)程序,增加一個(gè)抽象的運(yùn)算類。通過繼承、多態(tài)等面向?qū)ο笫侄?,隔離具體加法、減法與客戶端的耦合。這樣,需求仍然可以滿足,還能應(yīng)對變化。如果再要增加乘法、除法的功能,就不需要去更改加法、減法的類,而是增加乘法和除法子類就可。即面對需求,對程序的改動(dòng)是通過增加新代碼進(jìn)行的,而不改變現(xiàn)有的代碼。這就滿足了開-封原則(對擴(kuò)展開放,對修改關(guān)閉)。運(yùn)算類interfaceOperation{publicintgetResult(intnumberA,intnumberB);}classOperationAddimplementsOperation{publicintgetResult(intnumberA,intnumberB){returnnumberA+numberB;}}classOperationDivimplementsOperation{publicintgetResult(intnumberA,intnumberB){intresult=0;if(numberB!=0)result=numberA/numberB;else{System.out.println("除數(shù)不能為0。");System.exit(0);}returnresult;}}classOperationSubimplementsOperation{publicintgetResult(intnumberA,intnumberB){returnnumberA-numberB;}}classOperationMulimplementsOperation{publicintgetResult(intnumberA,intnumberB){returnnumberA*numberB;}}運(yùn)算接口中定義了getResult()方法用于得到結(jié)果,它有兩個(gè)參數(shù)用于計(jì)算器的操作數(shù)。加減乘除類都實(shí)現(xiàn)了運(yùn)算接口,重寫了getResult()方法,這樣修改任何一個(gè)算法,都不需要提供其他算法的代碼。但是,現(xiàn)在的問題是如何確定使用加減乘除中哪一個(gè)類?,F(xiàn)在的問題是如何實(shí)例化對象,到底實(shí)例化誰,將來會(huì)不會(huì)增加實(shí)例化的對象,比如增加求M的N次方的運(yùn)算,這是很容易變化的地方??梢钥紤]用一個(gè)單獨(dú)的類來做這個(gè)創(chuàng)造實(shí)例的過程,這就是工廠。簡單運(yùn)算工廠類如下。classOperationFactory{publicOperationcreateOperate(charoperate){Operationoper=null;switch(operate){case'+':oper=newOperationAdd();break;case'-':oper=newOperationSub();break;case'*':oper=newOperationMul();break;case'/':oper=newOperationDiv();break;}returnoper;}}客戶端客戶端代碼如下:classclientSimpleFactory{publicstaticvoidmain(String[]args){Operationoper;

oper=newOperationFactory().createOperate('+');intresult=oper.getResult(1,2);System.out.println("result="+result);}}這樣只需輸入運(yùn)算符號(hào),工廠就實(shí)例化出合適的對象,通過多態(tài)返回父類的方式實(shí)現(xiàn)了計(jì)算器結(jié)果。命令行客戶端代碼如下:importjava.io.*;classclientSimpleFactory{publicstaticvoidmain(String[]args){intintNumberA=0,intNumberB=0;try{BufferedReaderbufR=newBufferedReader(newInputStreamReader(System.in));System.out.print("請輸入數(shù)字A:");try{intNumberA=newInteger(bufR.readLine()).intValue();}catch(Exceptione){System.out.println(e);System.exit(0);}System.out.print("請輸入數(shù)字B:");try{intNumberB=newInteger(bufR.readLine()).intValue();}catch(Exceptione){System.out.println(e);System.exit(0);}Operationoper=newOperationFactory().createOperate('+'); intresult=oper.getResult(intNumberA,intNumberB); System.out.println("result="+result);}catch(Exceptione){System.out.println(e);}}}程序的執(zhí)行結(jié)果如下:

請輸入數(shù)字A:12請輸入數(shù)字B:3result=15簡單工廠模式實(shí)現(xiàn)計(jì)算器程序優(yōu)點(diǎn)不管控制臺(tái)程序,Windows程序,Web程序,PDA還是手機(jī)程序,都可以用這段代碼來實(shí)現(xiàn)計(jì)算器的功能。如果需要更改加法運(yùn)算,只改OperationAdd就可以了如果需要增加其他運(yùn)算,比如M的N次方,平方根,立方根,自然對數(shù),正弦余弦等,只要增加相應(yīng)的運(yùn)算子類就可以了。缺點(diǎn)還需要去修改運(yùn)算類工廠,在switch中增加分支。3.基于工廠方法模式的計(jì)算器程序在簡單工廠里,如果現(xiàn)在需要增加其他運(yùn)算,比如要加一個(gè)“求M的N次方”的功能,要先增加“求M的N次方”的功能類,再更改工廠方法。這需要給運(yùn)算工廠類的方法里加“Case”的分支條件來做判斷。這實(shí)際上是修改了原有的類,不但對擴(kuò)展開放了,對修改也開放了,這樣就違背了開放-封閉原則。采用工廠方法模式可以解決這個(gè)問題。工廠方法(FactoryMethod)模式定義一個(gè)用于創(chuàng)建對象的接口,讓子類決定實(shí)例化哪一個(gè)類。工廠方法模式實(shí)現(xiàn)計(jì)算器程序工廠類先構(gòu)建一個(gè)工廠接口。interfaceIFactory{ OperationCreateOperation();}工廠類然后加減乘除各建一個(gè)具體工廠去實(shí)現(xiàn)這個(gè)接口classAddFactoryimplementsIFactory{publicOperationCreateOperation(){returnnewOperationAdd();}}classSubFactoryimplementsIFactory{publicOperationCreateOperation(){returnnewOperationSub();}}工廠類classMlFactoryimplementsIFactory{publicOperationCreateOperation(){ returnnewOperationMul(); }}classDivFactoryimplementsIFactory{publicOperationCreateOperation(){returnnewOperationDiv();}}運(yùn)算類-不變interfaceOperation{publicintgetResult(intnumberA,intnumberB);}classOperationAddimplementsOperation{publicintgetResult(intnumberA,intnumberB){returnnumberA+numberB;}}運(yùn)算類-不變classOperationDivimplementsOperation{publicintgetResult(intnumberA,intnumberB){intresult=0;if(numberB!=0)result=numberA/numberB;else{System.out.println("除數(shù)不能為0。");System.exit(0);}returnresult;}}運(yùn)算類-不變classOperationSubimplementsOperation{publicintgetResult(intnumberA,intnumberB){returnnumberA-numberB;}}classOperationMulimplementsOperation{publicintgetResult(intnumberA,intnumberB){returnnumberA*numberB;}}客戶端客戶端代碼如下:classclientSimpleFactory{publicstaticvoidmain(String[]args){IFactoryoperFactory=newAddFactory();Operationoper=operFactory.CreateOperation();intresult=oper.getResult(intNumberA,intNumberB);System.out.println("result="+result);}}命令行客戶端代碼如下:importjava.io.*;classclientFactoryMethod{publicstaticvoidmain(String[]args){intintNumberA=0,intNumberB=0;try{BufferedReaderbufR=newBufferedReader(newInputStreamReader(System.in));System.out.print("請輸入數(shù)字A:");try{intNumberA=newInteger(bufR.readLine()).intValue();}catch(Exceptione){System.out.print(e);System.exit(0);}

System.out.print("請輸入數(shù)字B:");try{intNumberB=newInteger(bufR.readLine()).intValue();}catch(Exceptione){

System.out.println(e);System.exit(0);

}IFactoryoperFactory=newAddFactory();Operationoper=operFactory.CreateOperation();intresult=oper.getResult(intNumberA,intNumberB);System.out.println("result="+result);}catch(Exceptione){System.out.println(e);}}}程序的執(zhí)行結(jié)果如下:請輸入數(shù)字A:12請輸入數(shù)字B:3result=15工廠類根據(jù)依賴倒轉(zhuǎn)原則,把工廠類抽象出一個(gè)接口,這個(gè)接口只有一個(gè)方法——?jiǎng)?chuàng)建抽象產(chǎn)品的工廠方法。然后,所有要生產(chǎn)具體類的工廠,實(shí)現(xiàn)這個(gè)接口。這樣,一個(gè)簡單工廠模式的工廠類,變成了一個(gè)工廠抽象接口和多個(gè)具體生成對象的工廠。要增加“求M的N次方”的功能時(shí),只需要增加此功能的運(yùn)算類和相應(yīng)的工廠類,不需要更改原有的工廠類了。這樣沒有了修改的變化,只是擴(kuò)展的變化,完全符合了開-閉原則的精神。客戶端工廠方法模式實(shí)現(xiàn)時(shí),客戶端需要決定實(shí)例化哪一個(gè)工廠來實(shí)現(xiàn)運(yùn)算類,還是存在選擇判斷。也就是說,工廠方法模式把簡單工廠模式的內(nèi)部邏輯判斷移到了客戶端代碼來進(jìn)行。要增加功能,本來是改工廠類的,而現(xiàn)在是修改客戶端。但是一般情況下,修改客戶端的時(shí)候,修改的工作量也很小,比起簡單工廠模式也少得多。工廠方法模式是簡單工廠模式的進(jìn)一步抽象和推廣。由于使用了多態(tài)性,工廠方法模式保持了簡單工廠模式封裝對象創(chuàng)建過程的優(yōu)點(diǎn),克服了它違背開-封原則的缺點(diǎn)。集中封裝對象的創(chuàng)建,不需要做大的改動(dòng)就可更換對象,降低了客戶程序與產(chǎn)品對象的耦合。但工廠方法模式的缺點(diǎn)是由于每加一個(gè)產(chǎn)品,就需要加一個(gè)產(chǎn)品工廠的類,增加了很多類和方法,增加了額外的開發(fā)量和復(fù)雜性。6.6可維護(hù)性復(fù)用6.6.1可維護(hù)性復(fù)用的概念通常認(rèn)為,一個(gè)可維護(hù)性較好的系統(tǒng),就是復(fù)用率較高的系統(tǒng);而一個(gè)可復(fù)用性好的系統(tǒng),就是一個(gè)可維護(hù)性好的系統(tǒng)。但是實(shí)際上,可維護(hù)性和可復(fù)用性是兩個(gè)獨(dú)立的目標(biāo)。對于面向?qū)ο蟮能浖到y(tǒng)設(shè)計(jì)來說,在支持可維護(hù)性(Maintainability)的同時(shí),提高系統(tǒng)的可復(fù)用性(Reuseability)是一個(gè)核心的問題??删S護(hù)性復(fù)用是指在支持可維護(hù)性的同時(shí),提高系統(tǒng)的可復(fù)用性。傳統(tǒng)的復(fù)用(1)代碼的剪貼復(fù)用雖然代碼的剪貼復(fù)用比完全沒有復(fù)用好一些,但是代碼的剪貼復(fù)用在具體實(shí)施時(shí),要冒著產(chǎn)生錯(cuò)誤的風(fēng)險(xiǎn)。復(fù)用所能節(jié)省的初期投資十分有限。(2)算法的復(fù)用:各種算法比如排序算法得到了大量的研究。應(yīng)用程序編程時(shí)通常不會(huì)建立自己的排序算法,而是在得到了很好的研究的各種算法中選擇一個(gè)。(3)數(shù)據(jù)結(jié)構(gòu)的復(fù)用:隊(duì)列、列表等數(shù)據(jù)結(jié)構(gòu)得到了十分透徹的研究,可以方便地拿過來使用。可維護(hù)性與復(fù)用的關(guān)系傳統(tǒng)復(fù)用的缺陷就是復(fù)用常常是以破壞可維護(hù)性為代價(jià)的。比如兩個(gè)模塊A和B同時(shí)使用另一個(gè)模塊C中的功能。那么當(dāng)A需要C增加一個(gè)新的行為的時(shí)候,B有可能不需要、甚至不允許C增加這個(gè)新行為。如果堅(jiān)持使用復(fù)用,就不得不以系統(tǒng)的可維護(hù)性為代價(jià);而如果從保持系統(tǒng)的可維護(hù)性出發(fā),就只好放棄復(fù)用??删S護(hù)性與可復(fù)用性是有共同性的兩個(gè)獨(dú)立特性因此,重要的是支持可維護(hù)性的復(fù)用,也就是在保持甚至提高系統(tǒng)的可維護(hù)性的同時(shí),實(shí)現(xiàn)系統(tǒng)的復(fù)用。面向?qū)ο笤O(shè)計(jì)的復(fù)用面向?qū)ο蟮恼Z言(例如Java語言)中,數(shù)據(jù)的抽象化、繼承、封裝和多態(tài)性等語言特性使得一個(gè)系統(tǒng)可在更高的層次上提供可復(fù)用性。數(shù)據(jù)的抽象化和繼承關(guān)系使得概念和定義可以復(fù)用多態(tài)性使得實(shí)現(xiàn)和應(yīng)用可以復(fù)用而抽象化和封裝可以保持和促進(jìn)系統(tǒng)的可維護(hù)性復(fù)用的焦點(diǎn)不再集中在函數(shù)和算法等具體實(shí)現(xiàn)細(xì)節(jié)上而是集中在最重要的含有宏觀商業(yè)邏輯的抽象層次上。抽象層次的復(fù)用是在提高復(fù)用性的同時(shí)保持和提高可維護(hù)性的關(guān)鍵。在面向?qū)ο蟮脑O(shè)計(jì)中,可維護(hù)性復(fù)用是以設(shè)計(jì)原則和設(shè)計(jì)模式為基礎(chǔ)的。6.6.2可維護(hù)性復(fù)用與設(shè)計(jì)原則設(shè)計(jì)原則是提高一個(gè)系統(tǒng)可維護(hù)性的同時(shí),提高這個(gè)系統(tǒng)的可復(fù)用性的指導(dǎo)原則遵循這些設(shè)計(jì)原則可以有效地提高系統(tǒng)的復(fù)用性,同時(shí)提高系統(tǒng)的可維護(hù)性。設(shè)計(jì)原則“開-閉”原則里氏代換原則依賴倒轉(zhuǎn)原則組合聚合復(fù)用原則單一職責(zé)原則迪米特法則接口隔離原則……設(shè)計(jì)原則常用的面向?qū)ο笤O(shè)計(jì)原則包括7個(gè),這些原則并不是孤立存在的,它們相互依賴,相互補(bǔ)充。設(shè)計(jì)原則6.6.3可維護(hù)性復(fù)用與設(shè)計(jì)模式設(shè)計(jì)模式三大類別,主要有23個(gè)。創(chuàng)建模式結(jié)構(gòu)模式行為模式設(shè)計(jì)模式本身并不能保證一個(gè)系統(tǒng)的可復(fù)用性和可維護(hù)性,但是設(shè)計(jì)師運(yùn)用設(shè)計(jì)模式的思想設(shè)計(jì)系統(tǒng)可以提高系統(tǒng)設(shè)計(jì)的復(fù)用性和可維護(hù)性。設(shè)計(jì)模式的思想有助于提高設(shè)計(jì)師的設(shè)計(jì)風(fēng)格、設(shè)計(jì)水平,并促進(jìn)同行之間的溝通。設(shè)計(jì)模式的誕生與發(fā)展模式的誕生與定義Alexander給出了關(guān)于模式的經(jīng)典定義:每個(gè)模式都描述了一個(gè)在我們的環(huán)境中不斷出現(xiàn)的問題,然后描述了該問題的解決方案的核心,通過這種方式,我們可以無數(shù)次地重用那些已有的解決方案,無需再重復(fù)相同的工作。模式是在特定環(huán)境中解決問題的一種方案設(shè)計(jì)模式的誕生與發(fā)展設(shè)計(jì)模式的發(fā)展

1987年,KentBeck和WardCunningham借鑒Alexander的模式思想在程序開發(fā)中開始應(yīng)用一些模式,在OOPSLA會(huì)議上發(fā)表了他們的成果。1990年,OOPSLA與ECOOP聯(lián)合舉辦,ErichGamma和RichardHelm等人開始討論有關(guān)模式的話題(BruceAnderson主持),“四人組”正式成立,并開始著手進(jìn)行設(shè)計(jì)模式的分類整理工作。1991年,OOPSLA,BruceAnderson主持了首次針對設(shè)計(jì)模式的研討會(huì)。1992年,OOPSLA,Anderson再度主持研討會(huì),模式已經(jīng)逐漸成為人們討論的話題。注:OOPSLA(Object-OrientedProgramming,Systems,Languages&Applications,面向?qū)ο缶幊?、系統(tǒng)、語言和應(yīng)用大會(huì)),編程語言及軟件工程國際頂級(jí)會(huì)議,2010年改為SPLASH---Systems,Programming,LanguagesandApplications:SoftwareforHumanity設(shè)計(jì)模式的誕生與發(fā)展設(shè)計(jì)模式的發(fā)展1993年,KentBeck和GradyBooch贊助了第一次關(guān)于設(shè)計(jì)模式的會(huì)議,這個(gè)設(shè)計(jì)模式研究組織發(fā)展成為著名的HillsideGroup研究組。1994年,由HillsideGroup發(fā)起,在美國伊利諾伊州(Illinois)的AllertonPark召開了第1屆關(guān)于面向?qū)ο竽J降氖澜缧詴?huì)議,名為PLoP(PatternLanguagesofPrograms,編程語言模式會(huì)議),簡稱PLoP‘94。1995年,PLoP‘95仍在伊利諾伊州的AllertonPark舉行,“四人組”出版了《設(shè)計(jì)模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)》(DesignPatterns:ElementsofReusableObject-OrientedSoftware)一書,本書成為1995年最搶手的面向?qū)ο髸?,也成為設(shè)計(jì)模式的經(jīng)典書籍。設(shè)計(jì)模式的誕生與發(fā)展設(shè)計(jì)模式的發(fā)展從1995年至今,設(shè)計(jì)模式在軟件開發(fā)中得以廣泛應(yīng)用,在Sun的JavaSE/JavaEE平臺(tái)和Microsoft的.net平臺(tái)設(shè)計(jì)中就應(yīng)用了大量的設(shè)計(jì)模式。誕生了越來越多的與設(shè)計(jì)模式相關(guān)的書籍和網(wǎng)站,設(shè)計(jì)模式也作為一門獨(dú)立的課程或作為軟件體系結(jié)構(gòu)等課程的重要組成部分出現(xiàn)在國內(nèi)外研究生和大學(xué)教育的課堂上。設(shè)計(jì)模式的定義與分類設(shè)計(jì)模式的定義設(shè)計(jì)模式(DesignPattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過分類編目的、代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié),使用設(shè)計(jì)模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。設(shè)計(jì)模式的定義與分類設(shè)計(jì)模式的基本要素設(shè)計(jì)模式一般有如下幾個(gè)基本要素:模式名稱、問題、目的、解決方案、效果、實(shí)例代碼和相關(guān)設(shè)計(jì)模式,其中的關(guān)鍵元素包括以下四個(gè)方面:模式名稱(Patternname)問題(Problem)解決方案(Solution)效果(Consequences)設(shè)計(jì)模式的定義與分類設(shè)計(jì)

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論