版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
大話(huà)設(shè)計(jì)模式程序體現(xiàn)的設(shè)計(jì)模式理念目錄TOC\h\h第一部分設(shè)計(jì)模式概述\h第一章大學(xué)畢業(yè)了怎么辦?——設(shè)計(jì)模式概述\h第二部分接口型模式\h第二章學(xué)校招聘會(huì)——接口型模式介紹\h第三章我們班來(lái)了位新同學(xué)——適配器模式\h第四章金融危機(jī)股票還掙錢(qián)?——外觀模式\h第五章生日禮物——組合模式\h第六章蠟筆與毛筆——橋接模式\h第三部分責(zé)任型模式\h第七章?lián)艄膫骰ā?zé)任型模式\h第八章購(gòu)物車(chē)——單體模式\h第九章放風(fēng)者與偷竊者——觀察者模式\h第十章中介公司——中介者模式\h第十一章高老莊的故事——代理模式\h第十二章包子——享元模式\h第四部分構(gòu)造型模式\h第十三章可惡的皇帝——構(gòu)造型模式\h第十四章汽車(chē)組裝——生成器模式\h第十五章運(yùn)動(dòng)協(xié)會(huì)——工廠方法模式\h第十六章麥當(dāng)勞的雞腿—抽象工廠模式\h第十七章蘭州拉面館——原型模式\h第十八章月光寶盒——備忘錄模式\h第五部分操作型模式\h第十九章兒子的功課——操作型模式\h第二十章訂單處理——模板方法模式\h第二十一章金融危機(jī)何時(shí)休——狀態(tài)模式\h第二十二章還錢(qián)——策略模式\h第二十三章飯店點(diǎn)菜——命令模式\h第二十四章蘋(píng)果汁——解釋器模式\h第六部分?jǐn)U展型模式\h第二十五章多功能的手機(jī)——擴(kuò)展型模式\h第二十六章三明治——裝飾器模式\h第二十七章老公,有錢(qián)不?——迭代器模式\h第二十八章指揮工人工作——訪問(wèn)者模式\h第二十九章大學(xué)生畢業(yè)3條出路:學(xué)、仕、商——設(shè)計(jì)模式總結(jié)第一部分設(shè)計(jì)模式概述第一章大學(xué)畢業(yè)了怎么辦?——設(shè)計(jì)模式概述1.1大學(xué)畢業(yè)了怎么辦大B和小A是同一所大學(xué)的師兄弟,都是學(xué)計(jì)算機(jī)編程專(zhuān)業(yè)。大B在C大畢業(yè)在從事軟件開(kāi)發(fā)工作,大B是小A的校友兼師兄,大B在大學(xué)四年學(xué)了不少軟件開(kāi)發(fā)方面的東西,也學(xué)著編了些小程序,小A經(jīng)常會(huì)找?guī)熜謱W(xué)習(xí)一些關(guān)于編程方面的問(wèn)題。時(shí)間:12月2日20點(diǎn)地點(diǎn):大B房間人物:大B,小A這天,小A問(wèn)大B,大學(xué)畢業(yè)了怎么辦?小A:“常聽(tīng)人說(shuō):‘大學(xué)畢業(yè)=失業(yè)’!”大B:“不盡然吧!事實(shí)上還是有好多同學(xué)挺希望畢業(yè)的,有的人覺(jué)得在學(xué)校里學(xué)不到什么東西,或因?yàn)橄M约涸琰c(diǎn)獨(dú)立可以減輕家里負(fù)擔(dān)啊什么的?!毙:“畢業(yè)了,就是成人了。應(yīng)該對(duì)自己負(fù)責(zé)了,又覺(jué)得還不能獨(dú)自去面對(duì)社會(huì)?!贝驜:“這就是為什么我們大學(xué)畢業(yè)后會(huì)覺(jué)得痛苦,覺(jué)得自己沒(méi)有就業(yè)能力吧!不敢面對(duì)社會(huì)。有能力的人到哪里都不愁找不到好工作,相反欠缺工作經(jīng)驗(yàn)的年輕人,如果沒(méi)有一個(gè)正確的職業(yè)規(guī)劃、良好的求職動(dòng)機(jī)、成熟的求職技巧,可能到哪都會(huì)遇到不少困難和挫折?!毙:“我平時(shí)在學(xué)校都很努力學(xué)習(xí)啊,畢業(yè)后找工作真的很難嗎?”大B:“就現(xiàn)在社會(huì)形式而言,找到工作其實(shí)并不難的,難的是找到自己喜歡的工作?,F(xiàn)在的年輕人,大多都是喜歡‘錢(qián)多、活少、離家近、坐坐辦公室’的工作,但是在現(xiàn)實(shí)中是不太可能的。我個(gè)人建議,先找一份適合自己發(fā)展,能累積到很多實(shí)踐經(jīng)驗(yàn)的基層工作,有了工作經(jīng)驗(yàn),再找更理想的工作,或是在原有崗位往更高的崗位發(fā)展就不再那么難了?!毙:“那么師兄,你說(shuō)如何才能找到適合自己的工作呢?”大B:“我認(rèn)為吶:首先還是要了解下自己的綜合實(shí)力,再就是要密切留意下社會(huì)上的崗位需求,總得說(shuō)起來(lái)有三點(diǎn):1、我想做什么?2、我能做什么?3、市場(chǎng)要什么?”1.2什么是設(shè)計(jì)模式這天大B問(wèn)小A:“怎樣設(shè)計(jì)可復(fù)用的面向?qū)ο筌浖俊毙:“靠,師兄你這是考我么?”大B:“啥啊?我這是想看你在學(xué)校是不是真學(xué)到了東西?!毙:“得得得,那我就說(shuō)說(shuō)吧。設(shè)計(jì)模式是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過(guò)分類(lèi)編目的、代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。使用設(shè)計(jì)模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。設(shè)計(jì)模式于己于他人于系統(tǒng)都是多贏的,設(shè)計(jì)模式使代碼編制真正工程化,設(shè)計(jì)模式是軟件工程的基石,如同大廈的一塊塊磚石一樣?!贝驜:“我再考考你,用C++、Java、C#或VB.NET任意一種面向?qū)ο笳Z(yǔ)言實(shí)現(xiàn)一個(gè)簡(jiǎn)單程序?!毙不到幾分鐘就給大B一個(gè)程序。
/*
*@(#)Blah.java1.8299/03/18
*Copyright(c)1994-1999SunMicrosystems,Inc.
*901SanAntonioRoad,PaloAlto,California,94303,U.S.A.
*Allrightsreserved.
*ThissoftwareistheconfidentialandproprietaryinformationofSun
*Microsystems,Inc.("ConfidentialInformation").Youshallnot
*disclosesuchConfidentialInformationandshalluseitonlyin
*accordancewiththetermsofthelicenseagreementyouenteredinto
*withSun.
*/
packagejava.blah;
importjava.blah.blahdy.BlahBlah;
/**
*Classdescriptiongoeshere.
*
*@version1.8218Mar1999
*@authorFirstnameLastname
*/
publicclassBlahextendsSomeClass{
/*Aclassimplementationcommentcangohere.*/
*
*classVar2documentationcommentthathappenstobe
*morethanonelinelong
*/
privatestaticObjectclassVar2;
/**instanceVar1documentationcomment*/
publicObjectinstanceVar1;
/**instanceVar2documentationcomment*/
protectedintinstanceVar2;
/**instanceVar3documentationcomment*/
privateObject[]instanceVar3;
/**
publicclassBlahextendsSomeClass{
/*Aclassimplementationcommentcangohere.*/
*
*classVar2documentationcommentthathappenstobe
*morethanonelinelong
*/
privatestaticObjectclassVar2;
/**instanceVar1documentationcomment*/
publicObjectinstanceVar1;
/**instanceVar2documentationcomment*/
protectedintinstanceVar2;
/**instanceVar3documentationcomment*/
privateObject[]instanceVar3;
/**
*...constructorBlahdocumentationcomment...
*/
publicBlah(){
//...implementationgoeshere...
}
/**
*...methoddoSomethingdocumentationcomment...
*/
publicvoiddoSomething(){
//...implementationgoeshere...
}
/**
*...methoddoSomethingElsedocumentationcomment...
*@paramsomeParamdescription
*/
publicvoiddoSomethingElse(ObjectsomeParam){
//...implementationgoeshere...
}
}
1.3代碼規(guī)范大B:“呵呵呵,寫(xiě)得不錯(cuò),不虧是C大的高材生。”小A:“師兄你這不是在取笑我嘛。我還有好多問(wèn)題得請(qǐng)教你哩!”大B:“行行行……沒(méi)問(wèn)題。小師弟好學(xué),師兄哪能袖手旁觀的吶!對(duì)了,你寫(xiě)代碼的時(shí)候一定要注要代碼的規(guī)范?!毙:“代碼規(guī)范?”大B:“嗯,來(lái)來(lái)來(lái),我說(shuō)給你聽(tīng)。首先是要注意注釋文檔的格式,注釋文檔將用來(lái)生成HTML格式的代碼報(bào)告,所以注釋文檔必須書(shū)寫(xiě)在類(lèi)、域、構(gòu)造函數(shù)、方法、定義之前。注釋文檔由兩部分組成——描述、塊標(biāo)記。”例如:注釋
@authorLEI
@version1.102005-09-01
publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,IOException{
doPost(request,response);
}
大B:“看!前兩行為描述,描述完畢后,由@符號(hào)起頭為塊標(biāo)記?!贝驜:“然后是注釋的種類(lèi)。有文件頭注釋、構(gòu)造函數(shù)注釋、域注釋方法注釋、和定義注釋?!毙:“什么?注釋還有那么多的種類(lèi)的?我以前都沒(méi)有用心去記過(guò)它的喔。師兄能不能給我講講每一種注釋的功能和要求?。俊贝驜:“這有什么問(wèn)題哩!舉些例子來(lái)講,那樣你就容易理解多了?!毙:“嘿嘿!那感情好?!贝驜:“文件頭注釋已結(jié)束,需要注明該文件創(chuàng)建時(shí)間,文件名,命名空間信息。”例如:描述部分用來(lái)書(shū)寫(xiě)該類(lèi)的作用或者相關(guān)信息,塊標(biāo)記部分必須注明作者和版本。如:classWindowextendsBaseWindow{...}大B:“構(gòu)造函數(shù)注釋采用,描述部分注明構(gòu)造函數(shù)的作用,不一定有塊標(biāo)記部分。域注釋可以出現(xiàn)在注釋文檔里面,也可以不出現(xiàn)在注釋文檔里面。用的域注釋將會(huì)被認(rèn)為是注釋文檔出現(xiàn)在最終生成的HTML報(bào)告里面,而使用的注釋會(huì)被忽略。這個(gè)應(yīng)該注意!”例如:booleanisTrigerSuccess=false;又例如:booleanisTrigerSuccess=false;再例如:intx=1263732;大B:“還有就是方法注釋?zhuān)椒ㄗ⑨尣捎妹枋霾糠肿⒚鞣椒ǖ墓δ?,塊標(biāo)記部分注明方法的參數(shù),返回值,異常等信息。定義注釋?zhuān)?guī)則同域注釋。”小A:“喔……原注釋還真的是有那么多種類(lèi),每個(gè)種類(lèi)都有不同的功能哩!嘿嘿!看來(lái)以后我得更認(rèn)識(shí)學(xué)習(xí)才行哩!”大B:“呵呵……你能這么想就好嘍。對(duì)了,小A,注釋塊標(biāo)記你知道不?”小A:“注釋塊標(biāo)?嘿嘿,這個(gè)……也不知道……”大B:“沒(méi)關(guān)系,我給告訴你。首先是標(biāo)記的順序?!眽K標(biāo)記將采用如下順序:
…
*
*@param(classes,interfaces,methodsandconstructorsonly)
*@return(methodsonly)
*@exception(@throwsisasynonymaddedinJavadoc1.2)
*@author(classesandinterfacesonly,required)
*@version(classesandinterfacesonly,required.Seefootnote1)
*@see
*@since
*@serial(or@serialFieldor@serialData)
*@deprecated(seeHowandWhenToDeprecateAPIs)
*…
一個(gè)塊標(biāo)記可以根據(jù)需要重復(fù)出現(xiàn)多次,多次出現(xiàn)的標(biāo)記按照如下順序:
@author按照時(shí)間先后順序(chronological)
@param按照參數(shù)定義順序(declaration)
@throws按照異常名字的字母順序(alphabetically)
@see按照如下順序:
@see#field
@see#Constructor(Type,Type...)
@see#Constructor(Typeid,Typeid...)
@see#method(Type,Type,...)
@see#method(Typeid,Type,id...)
@seeClass
@seeClass#field
@seeClass#Constructor(Type,Type...)
@seeClass#Constructor(Typeid,Typeid)
@seeClass#method(Type,Type,...)
@seeClass#method(Typeid,Typeid,...)
@seepackage.Class
@seepackage.Class#field
@seepackage.Class#Constructor(Type,Type...)
@seepackage.Class#Constructor(Typeid,Typeid)
@seepackage.Class#method(Type,Type,...)
@seepackage.Class#method(Typeid,Type,id)
@seepackage
小A:“哇噻!塊標(biāo)記還可以按照時(shí)間先后順序,按照參數(shù)定義順序,按照異常名字的字母順序哩!師兄,你講得真詳細(xì)。看來(lái)我得好好得花點(diǎn)心思把它們都記下來(lái)才好哩!”大B:“能記住當(dāng)然好哩,我再給你講下標(biāo)記介紹?!盄param標(biāo)記@param后面空格后跟著參數(shù)的變量名字(不是類(lèi)型),空格后跟著對(duì)該參數(shù)的描述。在描述中第一個(gè)名字為該變量的數(shù)據(jù)類(lèi)型,表示數(shù)據(jù)類(lèi)型的名次前面可以有一個(gè)冠詞如:a,an,the。如果是int類(lèi)型的參數(shù)則不需要注明數(shù)據(jù)類(lèi)型。例如:
…
*@paramchthechar用用來(lái)……
*@param_imagetheimage用來(lái)……
*@param_num一個(gè)數(shù)字……
…
大B:“對(duì)于參數(shù)的描述如果只是一短語(yǔ),最好不要首字母大寫(xiě),結(jié)尾也不要句號(hào)。對(duì)于參數(shù)的描述是一個(gè)句子,最好不要首字母大寫(xiě),如果出現(xiàn)了句號(hào)這說(shuō)明你的描述不止一句話(huà)。如果非要首字母大寫(xiě)的話(huà),必須用句號(hào)來(lái)結(jié)束句子。(英文的句號(hào))”公司內(nèi)部添加ByRef和ByVal兩個(gè)標(biāo)記,例如:*@param_imagetheimageByRef用來(lái)……說(shuō)明該參數(shù)是引用傳遞(指針),ByVal可以省略,表示是值傳遞。大B:“代碼規(guī)范大概要點(diǎn)就是這些了。聽(tīng)起來(lái)好像很多,只要用心,其實(shí)也很容易記的?!毙:“嘿嘿!師兄,你太歷害了!”1.4初學(xué)代碼者常犯的錯(cuò)誤小A:“師兄,我經(jīng)常在寫(xiě)代碼的時(shí)候犯錯(cuò),你能不能教教我吶!”大B:“好啊!當(dāng)出現(xiàn)這些錯(cuò)誤的時(shí)候,要仔細(xì)的看看錯(cuò)誤提示,找出問(wèn)題所在,避免以后不再發(fā)生同樣的錯(cuò)誤。在這個(gè)過(guò)程當(dāng)中我們的經(jīng)驗(yàn)和水平也在不斷的提升。Java錯(cuò)誤,主要包括兩方面,一種是語(yǔ)法錯(cuò)誤,另一種是邏輯錯(cuò)誤。語(yǔ)法錯(cuò)誤,也就是我們的編碼不符合Java規(guī)范,在編譯的時(shí)候無(wú)法通過(guò)。通常,我們都是用javac編譯我們的源程序,如果代碼中存在語(yǔ)法錯(cuò)誤,比如某個(gè)表達(dá)式后缺少分號(hào)的時(shí)候,編譯器就會(huì)告訴我們錯(cuò)誤信息,編譯就此停止。邏輯錯(cuò)誤,也就是我們常說(shuō)的Bug,一般存在邏輯錯(cuò)誤的程序都是可以順利的被編譯器編譯產(chǎn)生相應(yīng)的字節(jié)碼文件,也就是class文件。但是,在執(zhí)行的時(shí)候,也就是javaourClass的時(shí)候,得出的結(jié)果并不是我們所希望的?!毙:“對(duì)!我在寫(xiě)代碼的時(shí)候就是經(jīng)常出現(xiàn)這樣的問(wèn)題,經(jīng)常都解決不了?!贝驜:“失敗是成功的他媽?zhuān)W(xué)習(xí)編程是沒(méi)有什么捷徑可以走的,要在不斷的學(xué)習(xí)和編碼的過(guò)程中,逐漸的積累經(jīng)驗(yàn),從開(kāi)始的模仿者變成最后的創(chuàng)作者。和學(xué)習(xí)其它的編程語(yǔ)言一樣,在開(kāi)始編碼的時(shí)候也會(huì)出現(xiàn)很多很多的錯(cuò)誤,而且有的錯(cuò)誤可能也是不斷的出現(xiàn)?!毙:“嗯嗯嗯……師兄說(shuō)得是!”1.5面向?qū)ο缶幊绦:“師兄,用任意一種面向?qū)ο笳Z(yǔ)言實(shí)現(xiàn),就是要用面向?qū)ο蟮木幊谭椒ㄈ?shí)現(xiàn),對(duì)嗎?”大B:“一般編程初學(xué)者都會(huì)遇到這樣的問(wèn)題,碰到問(wèn)題就直覺(jué)地用計(jì)算機(jī)能夠理解的邏輯來(lái)描述和表達(dá)待解決的問(wèn)題及具體的求解過(guò)程。其實(shí)這是用計(jì)算機(jī)的方式去考慮它,就好比計(jì)算器這個(gè)程序,先輸入兩個(gè)數(shù)和運(yùn)算符號(hào),再根據(jù)運(yùn)算符號(hào)判斷選擇如何運(yùn)算,得出結(jié)果。這樣是對(duì)的。但這樣的想法卻使得程序只為滿(mǎn)足實(shí)現(xiàn)當(dāng)前的需求,而程序就不容易維護(hù),不容易擴(kuò)展,也更不容易復(fù)用。也就達(dá)不到高質(zhì)量代碼的要求了。”小A:“師兄,你這樣一講我又不懂了,那怎么程序才能容易維護(hù),容易擴(kuò)展,也容易復(fù)用哩?”大B:“我再跟你講細(xì)點(diǎn)吧!順便也舉些例子,理解一點(diǎn)。發(fā)廣告郵件,廣告郵件列表存在數(shù)據(jù)庫(kù)里面。倘若用C來(lái)寫(xiě)的話(huà),一般會(huì)這樣思考,先把郵件內(nèi)容讀入,然后連接數(shù)據(jù)庫(kù),循環(huán)取郵件地址,調(diào)用本機(jī)的qmail的sendmail命令發(fā)送。然后考慮用Java來(lái)實(shí)現(xiàn),既然是OOP,就不能什么代碼都塞到main過(guò)程里面,于是就設(shè)計(jì)了三個(gè)類(lèi):一個(gè)類(lèi)是負(fù)責(zé)讀取數(shù)據(jù)庫(kù),取郵件地址,調(diào)用qmail的sendmail命令發(fā)送;一個(gè)類(lèi)是讀郵件內(nèi)容,MIME編碼成HTML格式的,再加上郵件頭;一個(gè)主類(lèi)負(fù)責(zé)從命令讀參數(shù),處理命令行參數(shù),調(diào)用發(fā)email的類(lèi)。把一件工作按照功能劃分為3個(gè)模塊分別處理,每個(gè)類(lèi)完成一件模塊任務(wù)。仔細(xì)的分析一下,你就會(huì)發(fā)現(xiàn)這樣的設(shè)計(jì)完全是從程序員實(shí)現(xiàn)程序功能的角度來(lái)設(shè)計(jì)的,或者說(shuō),設(shè)計(jì)類(lèi)的時(shí)候,是自底向上的,從機(jī)器的角度到現(xiàn)實(shí)世界的角度來(lái)分析問(wèn)題的。因此在設(shè)計(jì)的時(shí)候,就已經(jīng)把程序編程實(shí)現(xiàn)的細(xì)節(jié)都考慮進(jìn)去了,企圖從底層實(shí)現(xiàn)程序這樣的出發(fā)點(diǎn)來(lái)達(dá)到滿(mǎn)足現(xiàn)實(shí)世界的軟件需求的目標(biāo)。這樣的分析方法其實(shí)是不適用于Java這樣面向?qū)ο蟮木幊陶Z(yǔ)言。”小A:“為什么?”大B:“因?yàn)椋绻挠肅語(yǔ)言,封裝兩個(gè)C函數(shù),都會(huì)比Java實(shí)現(xiàn)起來(lái)輕松的多,邏輯上也清楚的多?!毙:“我倒覺(jué)得面向?qū)ο蟮木柙谟诳紤]問(wèn)題的思路是從現(xiàn)實(shí)世界的人類(lèi)思維習(xí)慣出發(fā)的,只要領(lǐng)會(huì)了這一點(diǎn),就領(lǐng)會(huì)了面向?qū)ο蟮乃季S方法?!贝驜:“這樣吧,我再舉一個(gè)非常簡(jiǎn)單的例子:假使現(xiàn)在需要寫(xiě)一個(gè)網(wǎng)頁(yè)計(jì)數(shù)器,客戶(hù)訪問(wèn)一次頁(yè)面,網(wǎng)頁(yè)計(jì)數(shù)器加1,計(jì)數(shù)器是這樣來(lái)訪問(wèn)的如:http://hostname/count.cgi?id=xxx后臺(tái)有一個(gè)數(shù)據(jù)庫(kù)表,保存每個(gè)id(一個(gè)id對(duì)應(yīng)一個(gè)被統(tǒng)計(jì)訪問(wèn)次數(shù)的頁(yè)面)的計(jì)數(shù)器當(dāng)前值,請(qǐng)求頁(yè)面一次,對(duì)應(yīng)id的計(jì)數(shù)器的字段加1(這里我們忽略并發(fā)更新數(shù)據(jù)庫(kù)表,出現(xiàn)的表鎖定的問(wèn)題)?!贝驜:“如果按照一般從程序?qū)崿F(xiàn)的角度來(lái)分析,我們會(huì)這樣考慮:首先是從HTTPGET請(qǐng)求取到id,然后按照id查數(shù)據(jù)庫(kù)表,獲得某id對(duì)應(yīng)的訪問(wèn)計(jì)數(shù)值,然后加1,更新數(shù)據(jù)庫(kù),最后向頁(yè)面顯示訪問(wèn)計(jì)數(shù)。小A:“現(xiàn)在假設(shè)一個(gè)沒(méi)有程序設(shè)計(jì)經(jīng)驗(yàn)的人,要怎樣來(lái)思考這個(gè)問(wèn)題的呢?會(huì)提出什么樣的需求呢?”大B:“你很可能會(huì)這樣想:我需要有一個(gè)計(jì)數(shù)器,這個(gè)計(jì)數(shù)器應(yīng)該有這樣的功能,刷新一次頁(yè)面,訪問(wèn)量就會(huì)加1,另外最好還有一個(gè)計(jì)數(shù)器清0的功能,當(dāng)然計(jì)數(shù)器如果有一個(gè)可以設(shè)為任意值的功能的話(huà),我就可以作弊了。做為一個(gè)沒(méi)有程序設(shè)計(jì)經(jīng)驗(yàn)的人來(lái)說(shuō),他完全不會(huì)想到對(duì)數(shù)據(jù)庫(kù)應(yīng)該如何操作,對(duì)于HTTP變量該如何傳遞,他考慮問(wèn)題的角度就是我有什么需求,我的業(yè)務(wù)邏輯是什么,軟件應(yīng)該有什么功能。”按照這樣的思路需要有一個(gè)計(jì)數(shù)器類(lèi)Counter,有一個(gè)必須的和兩個(gè)可選的方法:getCount()//取計(jì)數(shù)器值方法resetCounter()//計(jì)數(shù)器清0方法setCount()//設(shè)計(jì)數(shù)器為相應(yīng)的值方法把Counter類(lèi)完整的定義如下:
publicclassCounter{
publicintgetCount(intid){}
publicvoidresetCounter(intid){}
publicvoidsetCount(intid,intcurrentCount){}
}
解決問(wèn)題的框架已經(jīng)有了,來(lái)看一下如何使用Counter。在count.cgi里面調(diào)用Counter來(lái)計(jì)數(shù),程序片段如下:
//這里從HTTP環(huán)境里面取id值
...
CountermyCounter=newCounter();//獲得計(jì)數(shù)器
intcurrentCount=myCounter.getCount(id);//從計(jì)數(shù)器中取計(jì)數(shù)
//這里向客戶(hù)瀏覽器輸出
...
程序的框架全都寫(xiě)好了,剩下的就是實(shí)現(xiàn)Counter類(lèi)方法里面具體的代碼了,此時(shí)才去考慮具體的程序語(yǔ)言實(shí)現(xiàn)的細(xì)節(jié)。面向?qū)ο蟮乃季S方法其實(shí)就是我們?cè)诂F(xiàn)實(shí)生活中習(xí)慣的思維方式,是從人類(lèi)考慮問(wèn)題的角度出發(fā),把人類(lèi)解決問(wèn)題的思維方式逐步翻譯成程序能夠理解的思維方式的過(guò)程,在這個(gè)翻譯的過(guò)程中,軟件也就逐步被設(shè)計(jì)好了。大B:“在運(yùn)用面向?qū)ο蟮乃季S方法進(jìn)行軟件設(shè)計(jì)的過(guò)程中,最容易犯的錯(cuò)誤就是開(kāi)始分析的時(shí)候,就想到了程序代碼實(shí)現(xiàn)的細(xì)節(jié),因此封裝的類(lèi)完全是基于程序?qū)崿F(xiàn)邏輯,而不是基于解決問(wèn)題的業(yè)務(wù)邏輯?!?.6面向?qū)ο蟠驜“我給你個(gè)通俗的例子:面向?qū)ο驩O=面向?qū)ο蟮姆治鯫OA+面向?qū)ο蟮脑O(shè)計(jì)OOD+面向?qū)ο蟮木幊蘋(píng)OP;通俗的解釋就是萬(wàn)物皆對(duì)象,把所有的事物都看作一個(gè)個(gè)可以獨(dú)立的對(duì)象(單元),它們可以自己完成自己的功能,而不是像C那樣分成一個(gè)個(gè)函數(shù);現(xiàn)在純正的OO語(yǔ)言主要是Java和C#,C++也支持OO,C是面向過(guò)程的;你看這樣好理解多了吧?”小A:“是啊,這樣的話(huà)一下子就看懂了!呵呵……”1.7面向?qū)ο蟮奶卣鞔驜:“那小師弟,面向?qū)ο笏加行┦裁刺卣髁ǎ俊毙:“面向?qū)ο蟮娜齻€(gè)基本特征是:封裝、繼承、多態(tài)。”大B:“嗯,是的。那你能不能用圖來(lái)說(shuō)明?”小A:“用圖來(lái)說(shuō)明?可以的。下面這個(gè)是我寫(xiě)的圖(如圖1-1面向?qū)ο蠡咎卣魉荆?,還得請(qǐng)師兄多指教?!贝驜:“吼,不錯(cuò)嘛?!眻D1-1面向?qū)ο蠡咎卣?.8面向?qū)ο蟮膬?yōu)勢(shì)大B:“其實(shí)學(xué)習(xí)編程也沒(méi)什么很難的,我一開(kāi)始也不知道的,不過(guò)學(xué)做了軟件開(kāi)發(fā)幾年后,遇多了,還有更改最初想法的事件,就慢慢明白了它的道理?!毙:“呵呵……這就是經(jīng)驗(yàn)所得嘛!”大B:“像你這么好學(xué),一定能學(xué)好的!在我們生活中接觸得最多是‘面向?qū)ο缶幊碳夹g(shù)’,而‘面向?qū)ο缶幊碳夹g(shù)’也是面向?qū)ο蠹夹g(shù)中的一個(gè)組成部分。面向?qū)ο蠹夹g(shù)需要面向?qū)ο蟮姆治觯O(shè)計(jì)和編程技術(shù),也需要借助必要的建模和開(kāi)發(fā)工具?!毙:“師兄,能不能給我講講面向?qū)ο蟮膬?yōu)勢(shì)具體有哪些吶?”大B想,好學(xué)的小師弟,想想自己當(dāng)年要是也能向小師弟這么好學(xué)的話(huà),那肯定比現(xiàn)在學(xué)得好。大B:“行吶,我講給你聽(tīng)。1、要符合人們習(xí)慣的思維方法,便于分解大型的復(fù)雜多變的問(wèn)題。由于對(duì)象對(duì)應(yīng)于現(xiàn)實(shí)世界中的實(shí)體,因而可以很自然地按照現(xiàn)實(shí)世界中處理實(shí)體的方法來(lái)處理對(duì)象,軟件開(kāi)發(fā)者可以很方便地與問(wèn)題提出者進(jìn)行溝通和交流。2、易于軟件的維護(hù)和功能的增減。對(duì)象的封裝性及對(duì)象之間的松散組合,都給軟件的修改和維護(hù)帶來(lái)了方便。3、可重用性好。重復(fù)使用一個(gè)類(lèi)(類(lèi)是對(duì)象的定義,對(duì)象是類(lèi)的實(shí)例化),可以比較方便地構(gòu)造出軟件系統(tǒng),加上繼承的方式,極大地提高了軟件開(kāi)發(fā)的效率。4、與可視化技術(shù)相結(jié)合,改善了工作界面。隨著基于圖形界面操作系統(tǒng)的流行,面向?qū)ο蟮某绦蛟O(shè)計(jì)方法也將深入人心。它與可視化技術(shù)相結(jié)合,使人機(jī)界面進(jìn)入GUI時(shí)代?!毙:“就如Java語(yǔ)言,它都有哪些優(yōu)點(diǎn)吶?”大B:“Java是目前最流行的語(yǔ)言不是沒(méi)有道理的。1、最為顯著的優(yōu)點(diǎn)是它與平臺(tái)無(wú)關(guān).Java依靠它的運(yùn)行庫(kù)(RunTimeLibrary)獲得了以往任何一種語(yǔ)言都沒(méi)有的平臺(tái)無(wú)關(guān)性。同樣的代碼可以不用改動(dòng)就可在Windows、Solaris、Unix等各種軟硬件平臺(tái)上運(yùn)行。2、另外一個(gè)顯著的優(yōu)點(diǎn)是Java的類(lèi)C++語(yǔ)法。Java從C++發(fā)展而來(lái),對(duì)于當(dāng)今世界上眾多的c++程序員來(lái)說(shuō),Java顯得并不陌生。3、面向?qū)ο?。Java語(yǔ)言是完全面向?qū)ο蟮?,區(qū)別于C++的“半面向?qū)ο蟆?。目前面向?qū)ο蠹夹g(shù)已經(jīng)取代早期的結(jié)構(gòu)化程序設(shè)計(jì)方法而成為計(jì)算機(jī)界的標(biāo)準(zhǔn)技術(shù),因?yàn)槭聦?shí)證明面向?qū)ο蠹夹g(shù)處理復(fù)雜問(wèn)題的優(yōu)勢(shì)遠(yuǎn)非其他方法所能及。4、健壯。Java自已操縱內(nèi)存減少了內(nèi)存出錯(cuò)的可能性。Java還實(shí)現(xiàn)了真數(shù)組,避免了覆蓋數(shù)據(jù)的可能。這些功能特征大大縮短了開(kāi)發(fā)Java應(yīng)用程序的周期。Java提供Null指針檢測(cè)數(shù)組邊界檢測(cè)異常出口字節(jié)代碼校驗(yàn)。5、安全。Java最重要的一點(diǎn)保證是:Java的安全體系架構(gòu)。Java的安全性可從兩個(gè)方面得到保證。一方面,在Java語(yǔ)言里,象指針和釋放內(nèi)存等C++功能被刪除,避免了非法內(nèi)存操作。另一方面,當(dāng)Java用來(lái)創(chuàng)建瀏覽器時(shí),語(yǔ)言功能和瀏覽器本身提供的功能結(jié)合起來(lái),使它更安全。6、多線(xiàn)程。簡(jiǎn)言之為一項(xiàng)任務(wù)多點(diǎn)開(kāi)工,多線(xiàn)程帶來(lái)的更大的好處是更好的交互性能和實(shí)時(shí)控制性能。在Java里,你可用一個(gè)單線(xiàn)程來(lái)調(diào)一副圖片,而你可以訪問(wèn)HTML里的其它信息而不必等它。7、動(dòng)態(tài)。Java的動(dòng)態(tài)特性是其面向?qū)ο笤O(shè)計(jì)方法的發(fā)展。它允許程序動(dòng)態(tài)地裝入運(yùn)行過(guò)程中所需要的類(lèi),這是C++語(yǔ)言進(jìn)行面向?qū)ο蟪绦蛟O(shè)計(jì)所無(wú)法實(shí)現(xiàn)的?!毙:“哇噻!你不說(shuō)我還真不知道Java語(yǔ)言還有這么多優(yōu)點(diǎn)哩!嘿嘿!也真難怪現(xiàn)在最流行它了?!贝驜:“是??!不管哪種語(yǔ)言都有各自的優(yōu)缺點(diǎn),Java的缺點(diǎn)就是編譯、執(zhí)行的速度太慢,所以Java私塾建議你如果想學(xué)編程,不要總是問(wèn)這個(gè)好不好,那個(gè)難不難,只要下定決心學(xué)就對(duì)了?!?.9類(lèi)、對(duì)象、方法和實(shí)例變量這天,大B問(wèn)小A,“小師弟,你知道什么是類(lèi),對(duì)象,方法和實(shí)例變量嗎?”小A:“師兄,你問(wèn)得我早都學(xué)過(guò),不信,我說(shuō)給你聽(tīng)。類(lèi)是一種復(fù)雜的數(shù)據(jù)類(lèi)型,它是將不同類(lèi)型的數(shù)據(jù)和與這些數(shù)據(jù)相關(guān)的操作封閉在一起的集合體。類(lèi)是對(duì)一組事物的抽象,是對(duì)事物的特性和功能的描述。類(lèi)是一種模板,并不代表具體的事物。對(duì)象是類(lèi)的實(shí)例,即類(lèi)的變量。方法是指實(shí)現(xiàn)對(duì)象所具有的功能操作的代碼。每個(gè)對(duì)象中一般包括若干種方法,每個(gè)方法有方法名和對(duì)應(yīng)的一組代碼。方法體現(xiàn)了對(duì)象的一種行為能力。實(shí)例變量……實(shí)例變量……”大B:“哈哈!不記得了吧?”小A:“實(shí)例變量?”大B:“讓師兄來(lái)告訴你吧,實(shí)例變量就是說(shuō)某一實(shí)例具有的狀態(tài),比如說(shuō)圓的半徑,汽車(chē)的顏色?!毙:“喔……我明白了,嘿嘿,其實(shí)這個(gè)我學(xué)過(guò)的,只是……只是一時(shí)想不起來(lái)了……”大B:“沒(méi)事,我這次問(wèn)你,你不知道,下次遇到,你不就想起來(lái)了。對(duì)于初學(xué)者來(lái)說(shuō)要理解類(lèi)、對(duì)象、和對(duì)象變量不是一件很容易的事?,F(xiàn)以美眉為例來(lái)說(shuō)明。假設(shè)你的學(xué)?;蛘呤琴嵈竺椎牡胤接泻芏嗝烂?,為了和這些妹妹中的一部分或者全部建立良好的關(guān)系,你需要建立一個(gè)Java類(lèi):Meimei。那么學(xué)校種的美眉們就是類(lèi)Meimei,而對(duì)象就是類(lèi)的一個(gè)實(shí)例,那么其中任何一個(gè)美眉就是對(duì)象?!比纾?/p>
meimei1("Jennifer",...);
meimei2("Lucy",...);
meimei3("Danny",...);
......
假如你想讓其中一個(gè)Meimei類(lèi)實(shí)例成為你的‘超友誼朋友’,另外一個(gè)Meimei類(lèi)實(shí)例成為你的‘女朋友’,那么‘超友誼朋友’和‘女朋友’就是一個(gè)Meimei類(lèi)對(duì)象變量;‘超友誼朋友’和‘女朋友’這兩個(gè)對(duì)象變量就引用其中一個(gè)Meimei對(duì)象。如現(xiàn)在你的超友誼朋友是meimei1,你的女朋友是meimei2,那么:
超友誼朋友=meimei1;
女朋友=meimei2;
="Jennifer";
="Lucy";
="Danny"
超友誼朋友.name="Jennifer";
女朋友.name="Lucy";
三個(gè)月以后你的超友誼朋友是meimei3,你的女朋友是meimei1,那么:
超友誼朋友=meimei3;
女朋友=meimei1;
="Jennifer";
="Lucy";
="Danny";
超友誼朋友.name="Danny";
女朋友.name="Jennifer";
大B問(wèn)小A,:“這下你該對(duì)類(lèi),對(duì)象,方法又有新的認(rèn)識(shí)了吧?”小A:“嘿嘿!簡(jiǎn)直就是重新認(rèn)識(shí)??!哈哈!”1.10繼承大B:“那我再來(lái)問(wèn)你,你來(lái)講講繼承?!毙:“繼承是指一個(gè)對(duì)象直接使用另一對(duì)象的屬性和方法?!贝驜:“嗯!事實(shí)上,我們遇到的很多實(shí)體都有繼承的含義。例如,若把汽車(chē)看成一個(gè)實(shí)體,它可以分成多個(gè)子實(shí)體,如:卡車(chē)、公共汽車(chē)等。這些子實(shí)體都具有汽車(chē)的特性,因此,汽車(chē)是它們的‘父親’,而這些子實(shí)體則是汽車(chē)的‘孩子’?!?.11接口大B:“你知道什么是接口嗎?”小A:“這個(gè)我知道,接口用來(lái)定義一種程序的協(xié)定。實(shí)現(xiàn)接口的類(lèi)或者結(jié)構(gòu)要與接口的定義嚴(yán)格一致。有了這個(gè)協(xié)定,就可以?huà)侀_(kāi)編程語(yǔ)言的限制(理論上)。接口可以從多個(gè)基接口繼承,而類(lèi)或結(jié)構(gòu)可以實(shí)現(xiàn)多個(gè)接口。接口可以包含方法、屬性、事件和索引器。接口本身不提供它所定義的成員的實(shí)現(xiàn)。接口只指定實(shí)現(xiàn)該接口的類(lèi)或接口必須提供的成員?!笨吹叫煹苓€學(xué)得挺好的嘛!大B越來(lái)越欣賞小師弟了。大B說(shuō):“接口好比一種模版,這種模版定義了對(duì)象必須實(shí)現(xiàn)的方法,其目的就是讓這些方法可以作為接口實(shí)例被引用。接口不能被實(shí)例化。類(lèi)可以實(shí)現(xiàn)多個(gè)接口并且通過(guò)這些實(shí)現(xiàn)的接口被索引。接口變量只能索引實(shí)現(xiàn)該接口的類(lèi)的實(shí)例?!?.12UML圖小A:“師兄,我想請(qǐng)你幫我總結(jié)和理解一下類(lèi)圖,因?yàn)槲覍W(xué)了那么久的編程,類(lèi)圖就是學(xué)不好,簡(jiǎn)單的類(lèi)圖我還可以看懂,有些標(biāo)記很容易混淆。你能給我講講吧!”大B:“先看看UML的定義:統(tǒng)一建模語(yǔ)言(UnifiedModelingLanguage,UML)是一種繪制軟件藍(lán)圖的標(biāo)準(zhǔn)語(yǔ)言?!毙:“那它有什么特性?”大B:“顧名思義,它具備語(yǔ)言的特性:-標(biāo)準(zhǔn)性:元素、規(guī)則、機(jī)制-邏輯性:嚴(yán)謹(jǐn)-靈活性:同樣的事情,不同的正確表述-方言性:利益驅(qū)動(dòng);翻譯版本的混亂-不可盲目模仿性:避免片面借鑒,抓住事務(wù)本質(zhì)和思想靈魂”小A:“嘿嘿,標(biāo)準(zhǔn)性、邏輯性我能理解,什么是靈活性,方言性和不可肓目模仿性?”大B:“方言性,在一方面是由于軟件商家(如微軟)追求商業(yè)利益、行業(yè)標(biāo)準(zhǔn)的制定權(quán)和話(huà)語(yǔ)權(quán),造成了一些CASE工具未完全遵從UML標(biāo)準(zhǔn)這一混亂現(xiàn)象;另一方面,由于國(guó)內(nèi)翻譯的參考教材中文字晦澀難懂、不統(tǒng)一,造成目前的UML的學(xué)習(xí)門(mén)檻高、入門(mén)困難的局面。其實(shí),真的,這東西沒(méi)有這么高深。說(shuō)到方言性,不得不補(bǔ)充一句,不建議使用VISIO做為UML的CASE工具,UML的三個(gè)爸爸早在94、95年分別加入Rational公司,沒(méi)有理由不使用RationalRose啊。最值得一提的是它的靈活性、不可盲目模仿性。舉個(gè)例子吧!”用例場(chǎng)景:張無(wú)忌,出生于冰火島,父親張翠山,母親殷素素。張無(wú)忌的武功大全:武當(dāng)長(zhǎng)拳、九陽(yáng)神功、武當(dāng)梯云縱、乾坤大挪移、少林擒龍手、崆峒七傷拳、太極拳劍、圣火令武功。先畫(huà)個(gè)用例圖,描述張無(wú)忌他家的情況。如圖1-2用例圖所示圖1-2用例圖2)以泛化關(guān)系表示繼承的時(shí)候,用例描述中需要強(qiáng)調(diào)描述:兒子繼承了爸爸的什么,爸爸有哪些沒(méi)有被兒子繼承,兒子還新增了什么。如圖1-3用例圖所示圖1-3用例圖3)這是一個(gè)有問(wèn)題的用例圖,看看錯(cuò)誤在哪里?提示:聚合關(guān)系是一種松散的關(guān)聯(lián)關(guān)系,目標(biāo)元素可有可無(wú)。如圖1-4用例圖所示圖1-4用例圖想一想,人亡家還在么?所以以上關(guān)系用聚合是完全錯(cuò)誤的!那么,上面用例場(chǎng)景描述中,哪些可以使用聚合關(guān)系描述呢?圖1-5用例圖沒(méi)錯(cuò),張無(wú)忌可以不會(huì)任何武功,也可以會(huì)N多武功;張無(wú)忌學(xué)習(xí)九陽(yáng)神功,并不妨礙楊過(guò)、郭靖去學(xué)習(xí)嘛!如圖1-5用例圖所示4)這還是一個(gè)有問(wèn)題的用例,看看錯(cuò)誤在哪里?提示:組合關(guān)系是一種強(qiáng)關(guān)聯(lián),它有一個(gè)重要的特性:部分在某一時(shí)刻僅僅只能屬于一個(gè)整體。如圖1-6用例圖所示圖1-6用例圖想一想,殷素素不但是張翠山的老婆,還是殷家的女兒,張家的兒媳婦。有人問(wèn),這張用例圖中并未講到張家和殷家啊,所以這般描述好像也不錯(cuò)。非也,用例圖描述的是實(shí)際的、真實(shí)的關(guān)系,跟“人為地”畫(huà)或不畫(huà)是沒(méi)有任何關(guān)系的。所以以上關(guān)系用組合是完全錯(cuò)誤的!那么,上面用例場(chǎng)景描述中,哪些可以使用組合關(guān)系描述呢?我挖,我挖,我使勁挖,挖掘需求。5分鐘過(guò)后。突然想到:冰火島上有樹(shù),樹(shù)上長(zhǎng)葉子,嘿,有了!如圖1-7用例圖所示圖1-7用例圖現(xiàn)在是不是感覺(jué)UML很好玩?想不想了解一下UML的成長(zhǎng)歷程,想不想認(rèn)識(shí)一下它的三個(gè)爸爸?如圖1-8用例圖所示圖1-8用例圖UML之父:GradyBooch、JamesRumbaugh、IvarJacobsonGradyBooch在他的一本書(shū)中說(shuō):“如果你有好的思想,那么它也是我們的”。這其實(shí)從一方面概括了UML的哲學(xué)--它吸取已有的精華并且在其上進(jìn)行OOA/D(面向?qū)ο蠓治龊驮O(shè)計(jì))整合和構(gòu)造。這是最廣泛意義上的復(fù)用。大B:“在正式上手去應(yīng)用UML之前,再了解一下應(yīng)用UML的三種方式,包括:-UML作為草圖非正式的、不完整的圖(通常是在白板上手繪草圖),借助可視化語(yǔ)言的功能,用于探討問(wèn)題或解決方案空間的復(fù)雜部分。-UML作為藍(lán)圖(主要方式)這是UML更加正式和精確的用法,使用UML用于詳細(xì)規(guī)定軟件系統(tǒng)。UML模型可被維護(hù),并成為軟件的一個(gè)重要交付成果。用于:正向工程,逆向工程。這種方法需要使用如RationalRose建模工具。-UML作為編程語(yǔ)言使用模型驅(qū)動(dòng)構(gòu)架(ModelDrivenArchitecture,MDA),給UMl模型添加足夠的細(xì)節(jié),使得能夠從模型中編譯生成系統(tǒng)。這是UML最正式和精確的用法,是軟件開(kāi)發(fā)的未來(lái)。但目前在理論、工具的健壯性和可用性方面仍處于發(fā)展階段?!贝驜:“還有就是,類(lèi)圖這東西你以后看多了,用多了自然就熟悉了。”小A:“看來(lái)UML類(lèi)圖也不太難嘛!嘿嘿!”大B:“就是??!以后就要記住了哦!編程是一門(mén)技術(shù),也是一門(mén)藝術(shù)。不能只滿(mǎn)足于寫(xiě)代碼運(yùn)行結(jié)果正確,要考慮如何讓代碼更加簡(jiǎn)練,更加容易維護(hù),容易擴(kuò)展和復(fù)用,這樣才可以真正得到提高。UML類(lèi)圖不是一學(xué)就會(huì)的,要有一個(gè)慢慢熟練的過(guò)程。學(xué)無(wú)止境,理解面向?qū)ο蟮牟攀钦嬲龑W(xué)習(xí)編程的開(kāi)始!”第二部分接口型模式第二章學(xué)校招聘會(huì)——接口型模式介紹2.1學(xué)校招聘會(huì)這個(gè)星期六我校會(huì)舉辦校園招聘會(huì)。面對(duì)如此嚴(yán)峻的就業(yè)形式,小A雖然還不是畢業(yè)班,但是他想去參加這個(gè)星期六的招聘會(huì)。他想見(jiàn)識(shí)和感受一下現(xiàn)場(chǎng)招聘的氣氛,順便了解一下情況,提前做好準(zhǔn)備工作。時(shí)間:12月13日8點(diǎn)地點(diǎn):校東區(qū)體育場(chǎng)學(xué)校招聘會(huì)就設(shè)在我校東區(qū)休育場(chǎng),今天小A早早地來(lái)到這里。招聘的單位早已把整個(gè)操場(chǎng)占的滿(mǎn)滿(mǎn)的,但來(lái)應(yīng)聘的大學(xué)生還是把一個(gè)個(gè)單位圍的水瀉不通。這里可是我們天天打球,上體育課的地方吶!這里有我們的快樂(lè)和歡笑。如今,這里卻是處處嚴(yán)峻!轉(zhuǎn)了一上午,投了幾份簡(jiǎn)歷,雖然不是真的要來(lái)找工作的,但是今天的招聘會(huì)的確讓小A見(jiàn)識(shí)到了不少。小A想畢業(yè)后也會(huì)找一個(gè)工作,也會(huì)參加這樣的招聘會(huì)。覺(jué)得很不可思議,跟想像的差的太遠(yuǎn)了,還沒(méi)準(zhǔn)備好接受這些。但總有畢業(yè)的那天吧,總要面對(duì)這些的,生活真的很不容易……2.2接口型模式自從參加了學(xué)校招聘會(huì),小A就更加努力地學(xué)習(xí),他知道現(xiàn)在的社會(huì),不但是要講究學(xué)歷,工作經(jīng)驗(yàn),更講究的是個(gè)人的能力。小A把參加了學(xué)校招聘會(huì)的事給大B講了講。大B:“現(xiàn)實(shí)中學(xué)校操場(chǎng)的多功能,就如在系統(tǒng)的設(shè)計(jì)時(shí)刻常常遇到這樣一個(gè)問(wèn)題:類(lèi)Client的實(shí)例instanceClient希望使用另一個(gè)對(duì)象instanceX提供的服務(wù)service,但在設(shè)計(jì)時(shí),我們并不能確定對(duì)象instanceX究竟屬于哪個(gè)類(lèi)?!毙:“那遇到這些情況的時(shí)候,我們應(yīng)該怎么辦吶?”大B:“當(dāng)遇到這些情況,常見(jiàn)的解決辦法是:將對(duì)象instanceX提供的服務(wù)service抽象為一個(gè)接口ServiceProvider,然后讓對(duì)象instanceClient通過(guò)持有接口ServiceProvider的實(shí)例來(lái)使用服務(wù)service。這種通過(guò)接口間接獲得服務(wù)的解決方案就是接口模式?!毙:“喔……”大B:“接口模式還可以有一些變化的形式:不止用一個(gè)接口抽象一個(gè)對(duì)象提供的服務(wù),還可以用一組接口抽象一群對(duì)象的交互?!?.3接口型模式包括哪些模式大B:“你知道接口型有哪些模式嗎?”小A:“接口型模式包括:適配器模式,外觀模式,合成模式以及橋接模式等?!贝驜:“對(duì)!就是這些……要記住它喔!”2.4接口和抽象類(lèi)的區(qū)別小A:“在Java語(yǔ)言中,abstractclass和interface是支持抽象類(lèi)定義的兩種機(jī)制。那抽象類(lèi)和接口有什么區(qū)別?。俊贝驜:“abstractclass和interface之間在對(duì)于抽象類(lèi)定義的支持方面具有很大的相似性,甚至可以相互替換,因此很多開(kāi)發(fā)者在進(jìn)行抽象類(lèi)定義時(shí)對(duì)于abstractclass和interface的選擇顯得比較隨意。其實(shí),兩者之間還是有很大的區(qū)別的,對(duì)于它們的選擇甚至反映出對(duì)于問(wèn)題領(lǐng)域本質(zhì)的理解、對(duì)于設(shè)計(jì)意圖的理解是否正確、合理。”大B:“那你先來(lái)理解一下抽象類(lèi)?!毙心想師兄怎么問(wèn)我這么簡(jiǎn)單的問(wèn)題。“abstractclass和interface在Java語(yǔ)言中都是用來(lái)進(jìn)行抽象類(lèi)定義的?!贝驜:“那么什么是抽象類(lèi),使用抽象類(lèi)能為我們帶來(lái)什么好處呢?”小A:“好處?”大B:“嗯哼,對(duì),好處。說(shuō)說(shuō)看?”小A:“在面向?qū)ο蟮母拍钪?,我們知道所有的?duì)象都是通過(guò)類(lèi)來(lái)描繪的,但是反過(guò)來(lái)卻不是這樣。并不是所有的類(lèi)都是用來(lái)描繪對(duì)象的,如果一個(gè)類(lèi)中沒(méi)有包含足夠的信息來(lái)描繪一個(gè)具體的對(duì)象,這樣的類(lèi)就是抽象類(lèi)?!贝驜:“嗯。不錯(cuò)。抽象類(lèi)往往用來(lái)表征我們?cè)趯?duì)問(wèn)題領(lǐng)域進(jìn)行分析、設(shè)計(jì)中得出的抽象概念,是對(duì)一系列看上去不同,但是本質(zhì)上相同的具體概念的抽象。比如:如果我們進(jìn)行一個(gè)圖形編輯軟件的開(kāi)發(fā),就會(huì)發(fā)現(xiàn)問(wèn)題領(lǐng)域存在著圓、三角形這樣一些具體概念,它們是不同的,但是它們又都屬于形狀這樣一個(gè)概念,形狀這個(gè)概念在問(wèn)題領(lǐng)域是不存在的,它就是一個(gè)抽象概念。正是因?yàn)槌橄蟮母拍钤趩?wèn)題領(lǐng)域沒(méi)有對(duì)應(yīng)的具體概念,所以用以表征抽象概念的抽象類(lèi)是不能夠?qū)嵗?。在面向?qū)ο箢I(lǐng)域,抽象類(lèi)主要用來(lái)進(jìn)行類(lèi)型隱藏。”小A:“師兄,你這樣一講,我就不是很懂了。”大B:“沒(méi)關(guān)系,我跟你舉個(gè)例子先,在語(yǔ)法層面,Java語(yǔ)言對(duì)于abstractclass和interface給出了不同的定義方式,下面以定義一個(gè)名為Demo的抽象類(lèi)為例來(lái)說(shuō)明這種不同。使用abstractclass的方式定義Demo抽象類(lèi)的方式如下:
abstractclassDemo{
abstractvoidmethod1();
abstractvoidmethod2();
…
}
使用interface的方式定義Demo抽象類(lèi)的方式如下:
interfaceDemo{
voidmethod1();
voidmethod2();
…
}
大B:“你要知道,在abstractclass方式中,Demo可以有自己的數(shù)據(jù)成員,也可以有非abstract的成員方法,而在interface方式的實(shí)現(xiàn)中,Demo只能夠有靜態(tài)的不能被修改的數(shù)據(jù)成員(也就是必須是staticfinal的,不過(guò)在interface中一般不定義數(shù)據(jù)成員),所有的成員方法都是abstract的。從某種意義上說(shuō),interface是一種特殊形式的abstractclass。從編程的角度來(lái)看,abstractclass和interface都可以用來(lái)實(shí)現(xiàn)‘designbycontract’的思想。但是在具體的使用上面還是有一些區(qū)別的?!毙:“那它都有哪些區(qū)別呢?”這回小A可是不敢再把抽象型模式當(dāng)是個(gè)簡(jiǎn)單的問(wèn)題了。大B:“首先,abstractclass在Java語(yǔ)言中表示的是一種繼承關(guān)系,一個(gè)類(lèi)只能使用一次繼承關(guān)系(因?yàn)镴ava不支持多繼承--轉(zhuǎn)注)。但是,一個(gè)類(lèi)卻可以實(shí)現(xiàn)多個(gè)interface。也許,這是Java語(yǔ)言的設(shè)計(jì)者在考慮Java對(duì)于多重繼承的支持方面的一種折中考慮吧。其次,在abstractclass的定義中,我們可以賦予方法的默認(rèn)行為。但是在interface的定義中,方法卻不能擁有默認(rèn)行為,為了繞過(guò)這個(gè)限制,必須使用委托,但是這會(huì)增加一些復(fù)雜性,有時(shí)會(huì)造成很大的麻煩。在抽象類(lèi)中不能定義默認(rèn)行為還存在另一個(gè)比較嚴(yán)重的問(wèn)題,那就是可能會(huì)造成維護(hù)上的麻煩。因?yàn)槿绻髞?lái)想修改類(lèi)的界面(一般通過(guò)abstractclass或者interface來(lái)表示)以適應(yīng)新的情況(比如,添加新的方法或者給已用的方法中添加新的參數(shù))時(shí),就會(huì)非常的麻煩,可能要花費(fèi)很多的時(shí)間(對(duì)于派生類(lèi)很多的情況,尤為如此)。但是如果界面是通過(guò)abstractclass來(lái)實(shí)現(xiàn)的,那么可能就只需要修改定義在abstractclass中的默認(rèn)行為就可以了。同樣,如果不能在抽象類(lèi)中定義默認(rèn)行為,就會(huì)導(dǎo)致同樣的方法實(shí)現(xiàn)出現(xiàn)在該抽象類(lèi)的每一個(gè)派生類(lèi)中,違反了‘onerule,oneplace’原則,造成代碼重復(fù),同樣不利于以后的維護(hù)。因此,在abstractclass和interface間進(jìn)行選擇時(shí)要非常的小心?!毙:“嗯,好。下次我遇到abstractclass和interface時(shí)我一定會(huì)特別小心選擇的?!贝驜其實(shí)一開(kāi)始是看到小A對(duì)抽象類(lèi)和接口的區(qū)別不是很看重,也看到他對(duì)它們是有一定的理解,但是他還是想挫挫小A的銳氣。好讓他知道學(xué)習(xí)編程可是重重要認(rèn)真,就像做事一樣,不得馬虎。大B:“剛才我跟你講了從語(yǔ)法定義和編程的角度論述了abstractclass和interface的區(qū)別,這些層面的區(qū)別是比較低層次的、非本質(zhì)的?!贝驜:“來(lái),考慮這樣一個(gè)例子,假設(shè)在我們的問(wèn)題領(lǐng)域中有一個(gè)關(guān)于Door的抽象概念,該Door具有執(zhí)行兩個(gè)動(dòng)作open和close,此時(shí)我們可以通過(guò)abstractclass或者interface來(lái)定義一個(gè)表示該抽象概念的類(lèi)型?!倍x方式分別如下所示:使用abstractclass方式定義Door:
abstractclassDoor{
abstractvoidopen();
abstractvoidclose();
}
使用interface方式定義Door:
interfaceDoor{
voidopen();
voidclose();
}
大B:“其他具體的Door類(lèi)型可以extends使用abstractclass方式定義的Door或者implements使用interface方式定義的Door。看起來(lái)好像使用abstractclass和interface沒(méi)有大的區(qū)別。如果現(xiàn)在要求Door還要具有報(bào)警的功能。”小A:“我們?cè)撊绾卧O(shè)計(jì)針對(duì)該例子的類(lèi)結(jié)構(gòu)呢?”大B:“可以在Door的定義中增加一個(gè)alarm方法?!痹贒oor的定義中增加一個(gè)alarm方法
abstractclassDoor{
abstractvoidopen();
abstractvoidclose();
abstractvoidalarm();
}
或者
interfaceDoor{
voidopen();
voidclose();
voidalarm();
}
具有報(bào)警功能的AlarmDoor的定義方式如下:
classAlarmDoorextendsDoor{
voidopen(){…}
voidclose(){…}
voidalarm(){…}
}
或者
classAlarmDoorimplementsDoor{
voidopen(){…}
voidclose(){…}
voidalarm(){…}
}
大B:“你覺(jué)得這樣做行得通嗎?”小A:“起碼我是這樣認(rèn)為的!”大B:“好,有自信。不錯(cuò)!但是,我還是得和你講講你這樣做錯(cuò)在哪里了。你這種方法違反了面向?qū)ο笤O(shè)計(jì)中的一個(gè)核心原則ISP(InterfaceSegregationPrinciple),在Door的定義中把Door概念本身固有的行為方法和另外一個(gè)概念‘報(bào)警器’的行為方法混在了一起。這樣引起的一個(gè)問(wèn)題是那些僅僅依賴(lài)于Door這個(gè)概念的模塊會(huì)因?yàn)椤畧?bào)警器’這個(gè)概念的改變(比如:修改alarm方法的參數(shù))而改變,反之依然?!毙這回可是真的“受傷“了,誠(chéng)心地向師兄請(qǐng)教:“師兄,那你認(rèn)為應(yīng)該怎么做會(huì)比較好哩?請(qǐng)?jiān)劷??!贝驜:“呵呵。孺子可教也!好。我跟你講講。既然open、close和alarm屬于兩個(gè)不同的概念,根據(jù)ISP原則應(yīng)該把它們分別定義在代表這兩個(gè)概念的抽象類(lèi)中。定義方式有:這兩個(gè)概念都使用abstractclass方式定義;兩個(gè)概念都使用interface方式定義;一個(gè)概念使用abstractclass方式定義,另一個(gè)概念使用interface方式定義。顯然,由于Java語(yǔ)言不支持多重繼承,所以?xún)蓚€(gè)概念都使用abstractclass方式定義是不可行的。后面兩種方式都是可行的,但是對(duì)于它們的選擇卻反映出對(duì)于問(wèn)題領(lǐng)域中的概念本質(zhì)的理解、對(duì)于設(shè)計(jì)意圖的反映是否正確、合理?!毙還是似懂非懂的樣子。大B接著說(shuō):“我們一一來(lái)分析、說(shuō)明。如果兩個(gè)概念都使用interface方式來(lái)定義,那么就反映出兩個(gè)問(wèn)題:1、我們可能沒(méi)有理解清楚問(wèn)題領(lǐng)域,AlarmDoor在概念本質(zhì)上到底是Door還是報(bào)警器?2、如果我們對(duì)于問(wèn)題領(lǐng)域的理解沒(méi)有問(wèn)題,比如:我們通過(guò)對(duì)于問(wèn)題領(lǐng)域的分析發(fā)現(xiàn)AlarmDoor在概念本質(zhì)上和Door是一致的,那么我們?cè)趯?shí)現(xiàn)時(shí)就沒(méi)有能夠正確的揭示我們的設(shè)計(jì)意圖,因?yàn)樵谶@兩個(gè)概念的定義上(均使用interface方式定義)反映不出上述含義。如果我們對(duì)于問(wèn)題領(lǐng)域的理解是:AlarmDoor在概念本質(zhì)上是Door,同時(shí)它有具有報(bào)警的功能。我們?cè)撊绾蝸?lái)設(shè)計(jì)、實(shí)現(xiàn)來(lái)明確的反映出我們的意思呢?前面已經(jīng)說(shuō)過(guò),abstractclass在Java語(yǔ)言中表示一種繼承關(guān)系,而繼承關(guān)系在本質(zhì)上是‘is-a’關(guān)系。所以對(duì)于Door這個(gè)概念,我們應(yīng)該使用abstarctclass方式來(lái)定義。另外,AlarmDoor又具有報(bào)警功能,說(shuō)明它又能夠完成報(bào)警概念中定義的行為,所以報(bào)警概念可以通過(guò)interface方式定義?!比缦滤荆?/p>
abstractclassDoor{
abstractvoidopen();
abstractvoidclose();
}
interfaceAlarm{
voidalarm();
}
classAlarmDoorextendsDoorimplementsAlarm{
voidopen(){…}
voidclose(){…}
voidalarm(){…}
}
大B:“這種實(shí)現(xiàn)方式基本上能夠明確的反映出我們對(duì)于問(wèn)題領(lǐng)域的理解,正確的揭示我們的設(shè)計(jì)意圖。其實(shí)abstractclass表示的是‘is-a’關(guān)系,interface表示的是‘like-a’關(guān)系,大家在選擇時(shí)可以作為一個(gè)依據(jù),當(dāng)然這是建立在對(duì)問(wèn)題領(lǐng)域的理解上的,比如:如果我們認(rèn)為AlarmDoor在概念本質(zhì)上是‘報(bào)警器’,同時(shí)又具有Door的功能,那么上述的定義方式就要反過(guò)來(lái)了?!毙:“這回我是明白了?!贝驜還是不是很放心,接著說(shuō):“abstractclass和interface是Java語(yǔ)言中的兩種定義抽象類(lèi)的方式,它們之間有很大的相似性。但是對(duì)于它們的選擇卻又往往反映出對(duì)于問(wèn)題領(lǐng)域中的概念本質(zhì)的理解、對(duì)于設(shè)計(jì)意圖的反映是否正確、合理,因?yàn)樗鼈儽憩F(xiàn)了概念間的不同的關(guān)系(雖然都能夠?qū)崿F(xiàn)需求的功能)。這其實(shí)也是語(yǔ)言的一種的慣用法,這樣吧,我把我剛才講的都總結(jié)成幾點(diǎn),你記得時(shí)候方便一點(diǎn),也記得牢一點(diǎn)。1、abstractclass在Java語(yǔ)言中表示的是一種繼承關(guān)系,一個(gè)類(lèi)只能使用一次繼承關(guān)系。但是,一個(gè)類(lèi)卻可以實(shí)現(xiàn)多個(gè)interface。2、在abstractclass中可以有自己的數(shù)據(jù)成員,也可以有非abstarct的成員方法,而在interface中,只能夠有靜態(tài)的不能被修改的數(shù)據(jù)成員(也就是必須是staticfinal的,不過(guò)在interface中一般不定義數(shù)據(jù)成員),所有的成員方法都是abstract的。3、abstractclass和interface所反映出的設(shè)計(jì)理念不同。其實(shí)abstractclass表示的是‘is-a’關(guān)系,interface表示的是"like-a"關(guān)系。4、實(shí)現(xiàn)抽象類(lèi)和接口的類(lèi)必須實(shí)現(xiàn)其中的所有方法。抽象類(lèi)中可以有非抽象方法。接口中則不能有實(shí)現(xiàn)方法。5、接口中定義的變量默認(rèn)是publicstaticfinal型,且必須給其初值,所以實(shí)現(xiàn)類(lèi)中不能重新定義,也不能改變其值。6、抽象類(lèi)中的變量默認(rèn)是friendly型,其值可以在子類(lèi)中重新定義,也可以重新賦值。7、接口中的方法默認(rèn)都是public,abstract類(lèi)型的?!毙:“我把這些都記下來(lái),回去一定好好記住它!”2.5接口和委托的區(qū)別大B:“那你知道接口和委托的區(qū)別嗎?小A:“接口可以包含屬性,索引,方法以及事件。但委托不能包含事件?!按驜:“這回是對(duì)了。呵呵……別傷心,其實(shí)你學(xué)得很好,再加倍努力一定可以學(xué)得更好的!”小A今天可真是受益非淺吶。對(duì)大B師兄更多了一份敬意。小A:“謝謝師兄!你放心,我一定會(huì)更加努力!”第三章我們班來(lái)了位新同學(xué)——適配器模式3.1我們班來(lái)了位新同學(xué)——適配器模式時(shí)間:12月15日地點(diǎn):教室人物:06信管全班同學(xué)大二上學(xué)期的一天……早上到教室,依然是在響鈴前3分鐘。今天是上那討厭的匯編,學(xué)了我大半個(gè)學(xué)期,到現(xiàn)在還不會(huì)編。看來(lái)今天這個(gè)節(jié)我又得暈呼著過(guò)去了。正在我嘆氣的時(shí)候,教室里出現(xiàn)了騷動(dòng),還有好多人在竊竊私語(yǔ)哩。不少男生還吹起了口哨。怪了,今天有啥好事哩?正在我嘀咕的時(shí)候,班主任進(jìn)來(lái)了,教室門(mén)口走進(jìn)來(lái)一位美女?嘿嘿……還是金發(fā)的!不等我回神,班主任來(lái)了:“同學(xué)們,借大家上課前幾分鐘的時(shí)間,給大家說(shuō)個(gè)事。今天,我們班來(lái)了位新同學(xué),以后她會(huì)和大家一起學(xué)習(xí)。Anne,來(lái),給大家做個(gè)自我介紹?!迸_(tái)下一片騷動(dòng)……只見(jiàn)坐在我前面的金發(fā)MM站起來(lái)了。非常有禮貌地說(shuō)“Goodmorningeveryone,MynameisAnne,IamfromCanada,pleasetakecareof!”媽呀,英語(yǔ)?頭暈……只見(jiàn)她甜甜地笑著,我正暈呼,她接著說(shuō):“大家早上好,我叫Anne,我來(lái)自加拿大,請(qǐng)多關(guān)照!”這回可聽(tīng)懂了,人家叫安妮哩!人漂亮名字也好聽(tīng),這回可得迷倒我們班男生了。也難怪,在我理工院校,女生少之又少,這回突然來(lái)了位金發(fā)MM,我們班男生可有福了。不過(guò)那個(gè)MM也真是的,都會(huì)中文,為啥來(lái)個(gè)英語(yǔ)啊!看來(lái)接下來(lái)我們的大學(xué)生活就熱鬧了……3.2適配器模式時(shí)間:12月16日地點(diǎn):大B房間人物:大B,小A都說(shuō)學(xué)好普通話(huà),走遍中國(guó)都不怕。就好像Anne來(lái)到我們班,如果說(shuō)她只會(huì)說(shuō)英文,那我們好大一部份同學(xué)都不一定聽(tīng)得懂。可是她還會(huì)說(shuō)中文,那以后和大家在一起溝通就好多了。就好比我們講的適配器。大B:“師弟,你知道怎樣是適配器模式嗎?”小A:“就是把一個(gè)類(lèi)的借口轉(zhuǎn)換成客戶(hù)端所期待的另一種接口,從而使原接口不匹配而無(wú)法在一起工作的兩個(gè)類(lèi)能在一起工作。”大B:“從功能上講這些接口不兼容的類(lèi)一般具有相同或相似的功能。通常我們通過(guò)修改該類(lèi)的接口來(lái)解決這種接口不兼容的情形,但是如果我們不愿意為了一個(gè)應(yīng)用而修改各原有的接口,或者我們壓根就沒(méi)有原有對(duì)象的源代碼那該怎么辦呢?此時(shí)Adapter模式就會(huì)派上大用場(chǎng)了。你能不能用代碼來(lái)實(shí)現(xiàn)吶?”小A:“好。我試一下?!比绻袃蓚€(gè)編譯好的(無(wú)源代碼)類(lèi),類(lèi)A有某些功能,但是需要一個(gè)xml讀取模塊才能工作,這個(gè)模塊要實(shí)現(xiàn)這個(gè)接口:
publicinterfaceXmlReader{
publicInputStreamxmlReader();
}
你的另一個(gè)類(lèi)B恰好有這個(gè)功能,但是B實(shí)現(xiàn)的是這個(gè)接口:
publicinterfaceReaderXml{
publicInputStreamreaderXml();
}
這個(gè)時(shí)候我們的做法是寫(xiě)個(gè)適配器:
publicclassAdapterimplementsXmlReaderextendsB{
publicInputStreamxmlReader(){
returnreaderXml();
}
}
這個(gè)就是適配器模式了。適配器模式還有另外一種實(shí)現(xiàn)方式:
publicclassAdapterimplementsXmlReader
ReaderXmlb=newB();
publicInputStreamxmlReader(){
returnb.readerXml();
}
}
大B:“對(duì),沒(méi)錯(cuò)!上次有個(gè)朋友從美國(guó)給我?guī)Щ匾粋€(gè)微波爐,但因?yàn)槊绹?guó)的生活用電電壓是110V,而中國(guó)的電壓是220V,所以我不能使用,幸好朋友有先見(jiàn)之明,給我?guī)Щ匾粋€(gè)變壓器,能把220V電壓轉(zhuǎn)換成110V電壓,我才可以放心使用了?!毙:“嘿嘿!師兄你那位朋友還挺有心的嘛!一定是位很要好的朋友吧?”大B:“還不就是那個(gè)大學(xué)時(shí)候的死黨老E,那鳥(niǎo)人大學(xué)畢業(yè)后一直在國(guó)外,聽(tīng)說(shuō)最近要回來(lái)一趟哩!”小A:“是嗎?那到時(shí)你們可爽了,又可以一起喝酒啦!”大B:“嘿嘿!是啊!畢業(yè)幾年一直沒(méi)見(jiàn)過(guò)那鳥(niǎo)人,跑?chē)?guó)外喝了幾年養(yǎng)墨水,回來(lái)一定得好好宰他一頓。”小A:“那是要的啦!”大B:“對(duì)了,你編程學(xué)得不錯(cuò),能不能把剛才我說(shuō)的,也就是微波爐電壓轉(zhuǎn)換用代碼表示?”小A:“好。通過(guò)適配,使c220類(lèi)能在c110類(lèi)中使用?!背绦虼a:
#include
classc220v
{
public:
voidDianYa220v()
{
cout"220v電壓!"DianYa220v();
cout"經(jīng)變壓器轉(zhuǎn)換成""110v電壓"
運(yùn)行結(jié)果:220v電壓!經(jīng)變壓器轉(zhuǎn)換成110v電壓大B:“吼!非常不錯(cuò)喔!”3.3適配器模式的幾個(gè)要素大B:“那適配器模式有幾個(gè)要素?”小A:“我道還沒(méi)有注意,給我說(shuō)說(shuō)適配器模式所涉及的角色有哪些吧!”大B:“適配器模式所涉及的角色包括:目標(biāo)、客戶(hù)、被適配者、適配器?!毙:“那這些要素主要都做些什么?”大B:“目標(biāo)(CTarget):定義一個(gè)客戶(hù)端使用的特定接口??蛻?hù)(CClient):使用目標(biāo)接口,與和目標(biāo)接口一致的對(duì)象合作。被適配者(CAdaptee):一個(gè)現(xiàn)存需要匹配的接口。適配器(CAdapter):負(fù)責(zé)將CAdaptee的接口轉(zhuǎn)換成CTarget的接口。適配器是一個(gè)具體的類(lèi),這是本模式的核心。由此可見(jiàn),但客戶(hù)端調(diào)用Adapter接口時(shí)候,Adapter便會(huì)調(diào)用Adaptee的操作相應(yīng)請(qǐng)求,該模式就完成了接口的適配過(guò)程。”3.4優(yōu)勢(shì)和缺陷小A:“那適配器模式好在哪里?它又有什么缺陷吶?給我講講吧?”大B:“適配器模式可以將一個(gè)類(lèi)的接口和另一個(gè)類(lèi)的接口匹配起來(lái),使用的前提是你不能或不想修改原來(lái)的適配器母接口。例如,你向第三方購(gòu)買(mǎi)了一些類(lèi)、控件,但沒(méi)有源程序,這時(shí),使用適配器模式,你可以統(tǒng)一對(duì)象訪問(wèn)接口,但客戶(hù)調(diào)用可能需要變動(dòng)?!?.5何時(shí)使用適配器模式小A:“使用一個(gè)已經(jīng)存在的類(lèi),如果它的接口,方法和你的要求不相同的時(shí)候,可以考慮用適配器模式嗎?”大B:“可以??!如果兩個(gè)類(lèi)所做的事情相同或相似,但是他們有不同的接口的時(shí)候要使用它。類(lèi)都是共享同一個(gè)接口,那你想客戶(hù)代碼要怎么樣才行?”小A:“客戶(hù)代碼只要統(tǒng)一調(diào)用同一接口就行了,是不是這樣簡(jiǎn)單,直接,更緊湊?”大B:“是的,軟件都是需要維護(hù)的,維擴(kuò)可能會(huì)因不同的開(kāi)發(fā)人員,不同的產(chǎn)品,不同的廠家,造成功能類(lèi)似但是接口不同,這時(shí)就可以使用適配器?!毙:“你是說(shuō),在軟件開(kāi)發(fā)后期或維護(hù)的時(shí)候再考慮使用適配器?”大B:“在設(shè)計(jì)階段沒(méi)必要把類(lèi)似的功能類(lèi)的接口設(shè)計(jì)的不同?!毙:“可是不同的程序員定義方法的名稱(chēng)也可能是不同的呀!”大B:“那也是,但是在一般公司內(nèi)部,類(lèi)和方法的命名是有規(guī)范的,做好前期就設(shè)計(jì),接口不相同的時(shí)候,第一時(shí)間不應(yīng)該考慮用適配器,而是考慮通過(guò)重構(gòu)統(tǒng)一接口?!毙:“也就是說(shuō)要在雙方都不太容易修改的時(shí)候,這個(gè)時(shí)候再使用適配器模式適配?不是一出現(xiàn)不同時(shí)就使用它?會(huì)不會(huì)有在設(shè)計(jì)初就考慮用適配器模式的情況哩?”大B:“有,就好像在設(shè)計(jì)一個(gè)系統(tǒng)時(shí)使用第三方開(kāi)發(fā)組件,這個(gè)組件的接口與系統(tǒng)接口不相同,這個(gè)時(shí)候就不用為了迎合它去改動(dòng)自己的接口,在這種情況下,雖然是在開(kāi)發(fā)設(shè)計(jì)階段,解決接口不同的問(wèn)題也可以用適配器模式?!毙:“這樣吶!”大B:“有人舉過(guò)這樣一個(gè)例子:虎與飛禽是沒(méi)有直接關(guān)聯(lián)的兩類(lèi)動(dòng)物,但是現(xiàn)在出來(lái)了個(gè)“飛虎”,它同時(shí)具有虎肉食動(dòng)物跟飛禽會(huì)飛的特質(zhì),要在飛禽這個(gè)類(lèi)系中添加一個(gè)成員類(lèi)“飛虎”,除了直接實(shí)現(xiàn)“飛虎”類(lèi),還有一種簡(jiǎn)單的辦法是實(shí)現(xiàn)一個(gè)Adapter類(lèi),在其中包容一個(gè)虎的對(duì)象,同時(shí)實(shí)現(xiàn)飛禽的接口即可。當(dāng)然,對(duì)于這個(gè)問(wèn)題,多繼承或者實(shí)現(xiàn)多接口可能是一個(gè)更直觀的作法,在實(shí)際應(yīng)用中,可視具體需要確定采用何種作法?!?.6適配器總體上可以分為哪兩類(lèi)小A:“適配器還要有類(lèi)別之分的嗎?大B:“是啊,根據(jù)重用使用方式的不同一般將適配器模式分為兩類(lèi)。”小A:“喔。是嗎?哪兩類(lèi)哩?”大B:“類(lèi)適配器和對(duì)象適配器?!?.7類(lèi)適配器VS對(duì)象適配器大B:“我還是跟你講講類(lèi)適配器和對(duì)象適配器吧!舉些例子,這樣你就明白了?!毙:“好!”大B:“要正確地區(qū)別這兩種適配器的區(qū)別,我們還是從一個(gè)簡(jiǎn)單的例子開(kāi)始吧!我們的系統(tǒng)中有一個(gè)具有某個(gè)特定功能的類(lèi)Adaptee,一個(gè)客戶(hù)類(lèi)Client――他需要一個(gè)實(shí)現(xiàn)Target接口的對(duì)象,和一個(gè)Target接口。”以下是他們的源碼:
//Adaptee.java
publicclassAdaptee{
publicvoidspecialRequest(){
System.out.println("CalledSpecificRequest()inAdaptee");
}
}
//Client.java
publicclassClient{
publicstaticvoidmain(String[]args){
Targett=…… //newAdapter();
t.request();
}
}
//Target.java
publicinterfaceTarget{
publicvoidrequest();
}
“根據(jù)上一小節(jié)的分析我們知道此時(shí)需要一個(gè)Adapter對(duì)象,該對(duì)象實(shí)現(xiàn)Target接口,同時(shí)他又重用現(xiàn)有的Adaptee類(lèi)。任何有一點(diǎn)點(diǎn)OO(面向?qū)ο螅┲R(shí)的人都會(huì)想到通過(guò)繼承可以達(dá)到重用的目的?!毕旅媸峭ㄟ^(guò)繼承實(shí)現(xiàn)Adaptee類(lèi)重用的例子:
//Adapter.java
publicclassAdapterextendsAdapteeimplementsTarget{
publicvoidrequest(){
this.specialRequest();
}
}
大B:“看,簡(jiǎn)單明了吧!現(xiàn)在的過(guò)程就是:客戶(hù)調(diào)用Target接口的request方法,實(shí)際就是調(diào)用其父類(lèi)Adaptee的specialRequest方法?!毙:“嘿嘿!這樣一說(shuō)倒真的是簡(jiǎn)單喔!”大B:“對(duì)?。∵@就是大家通常常說(shuō)的類(lèi)的適配器!類(lèi)適配器具有以下的兩個(gè)特點(diǎn):1、適配器類(lèi)(Adapter)實(shí)現(xiàn)Target接口;2、適配器類(lèi)(Adapter)通過(guò)繼承來(lái)實(shí)現(xiàn)對(duì)Adaptee類(lèi)的重用?!毕旅媸且粋€(gè)通過(guò)組合關(guān)系實(shí)現(xiàn)繼承的例子,以下是源碼:
//Adapter.java
publicclassAdapterimplementsTarget{
Adapteeadaptee=newAdaptee();
publicvoidrequest(){
adaptee.specialRequest();
}
}
對(duì)于這兩者不同的適配器客戶(hù)代碼其實(shí)是完全一樣的。以下是客戶(hù)的代碼:
//Client.java
publicclassClient{
publicstaticvoidmain(String[]args){
Targett=newAdapter();
t.request();
}
}
大B:“現(xiàn)在可是全明白了吧?”小A:“嘿嘿!現(xiàn)在都懂了。”3.8類(lèi)適配器和對(duì)象適配器的哪些不同?小A:“那類(lèi)適配器和對(duì)象適配器有哪些不同哩?”大B:“類(lèi)適配器是通過(guò)繼承類(lèi)適配者類(lèi)(AdapteeClass)實(shí)現(xiàn)的,另外類(lèi)適配器實(shí)現(xiàn)客戶(hù)類(lèi)所需要的接口。當(dāng)客戶(hù)對(duì)象調(diào)用適配器類(lèi)方法的時(shí)候,適配器內(nèi)部調(diào)用它所繼承的適配者的方法。對(duì)象適配器包含一個(gè)適配器者的引用(reference),與類(lèi)適配器相同,對(duì)象適配器也實(shí)現(xiàn)了客戶(hù)類(lèi)需要的接口。當(dāng)客戶(hù)對(duì)象調(diào)用對(duì)象適配器的方法的時(shí)候,對(duì)象適配器調(diào)它所包含的適配器者實(shí)例的適當(dāng)方法。”3.9日常生活中的適配器大B:“適配器的例子在日常生活中隨處可見(jiàn)。”小A:“喔?”大B:“新的電腦鼠標(biāo)一般都是USB接口,而舊的電腦機(jī)箱上根本就沒(méi)有USB接口,而只有一個(gè)PS2接口,這時(shí)就必須有一個(gè)PS2轉(zhuǎn)USB的適配器,將PS2接口適配為USB接口。一般家庭中電源插座有的是兩個(gè)孔(兩項(xiàng)式)的,也有三個(gè)孔(三項(xiàng)式)的。很多時(shí)候我們可能更多地使用三個(gè)引腳的插頭,但是那種兩孔的插座就不能滿(mǎn)足我們的需求,此時(shí)我們一般會(huì)買(mǎi)一個(gè)拖線(xiàn)板,該拖線(xiàn)板的插頭是是兩腳插頭,這樣就可以插入原先的兩孔插座,同時(shí)拖線(xiàn)板上帶有很多兩孔、三孔的插座!這樣不僅可以擴(kuò)容,更主要的是將兩孔的插座轉(zhuǎn)變?yōu)槿椎牟遄 毙:“嘿嘿!仔細(xì)想來(lái)好像是有好多適配器的例子喔!”大B:“設(shè)計(jì)模式里的適配器模式和日常生活中的適配器的作用是完全一樣的。”3.10電腦電源適配器小A想去電腦城買(mǎi)個(gè)筆記本電腦電源適配器,這天他來(lái)找?guī)熜窒攘私庖恍╆P(guān)于電腦電源適配器。小A:“師兄,什么樣的是筆記本電腦的電源適配器?”大B:“多數(shù)筆記本電腦的電源適配器可以自動(dòng)檢測(cè)100~240V交流電(50/60Hz)?;旧纤械墓P記本電腦都把電源外置,用一條線(xiàn)和主機(jī)連接,這樣可以縮小主機(jī)的體積和重量,只有極少數(shù)的機(jī)型把電源內(nèi)置在主機(jī)內(nèi)。在電源適配器上都有一個(gè)銘牌,上面標(biāo)示著功率,輸入輸出電壓和電流量等指標(biāo),特別要注意輸入電壓的范圍,這就是所謂的‘旅行電源適配器’,如果到市電電壓只有100V的國(guó)家時(shí),這個(gè)特性就很有用了,有些水貨筆記本電腦是只在原產(chǎn)地銷(xiāo)售的,沒(méi)有這種設(shè)計(jì),甚至只有100V的單一輸入電壓,在我國(guó)的220V市電電壓下插上就會(huì)燒毀?!毙:“電源適配器?”大B:“嗯,對(duì)。電源適配器是小型便攜式電子設(shè)備及電子電器的供電電源變換設(shè)備,一般由外殼、電源變壓器和整流電路組成,按其輸出類(lèi)型可分為交流輸出型和直流輸出型;按連接方式可分為插墻式和桌面式。廣泛配套于電話(huà)子母機(jī)、游戲機(jī)、語(yǔ)言復(fù)讀機(jī)、隨身聽(tīng)、筆記本計(jì)算機(jī)、蜂窩電話(huà)等設(shè)備中?!毙:“師兄,手提電腦電源適配器要怎么買(mǎi)才好???”大B:“呵呵!這樣說(shuō)起來(lái)要注意的問(wèn)題就多了喔!”小A:“是么?那電源適配器的標(biāo)稱(chēng)電壓和電流是什么意思???”大B:“首先,一般電源適配器(以下簡(jiǎn)稱(chēng)電源)標(biāo)稱(chēng)的電壓,是指開(kāi)路輸出的電壓,也就是外面不接任何負(fù)載,沒(méi)有電流輸出時(shí)候的電壓,所以也可以理解為,此電壓就是電源輸出電壓的上限。對(duì)于電源內(nèi)部使用了主動(dòng)穩(wěn)壓的元件的情況下,即使市電電壓有所波動(dòng),其輸出也是恒定值,象市面上一般的小變壓器,比如隨身聽(tīng)之類(lèi)配的電源,如果市電波動(dòng),該電源的輸出也會(huì)隨之波動(dòng)的。一般來(lái)講普通電源適配器的真正空載電壓也不一定和標(biāo)稱(chēng)電壓完全一致,因?yàn)殡娮釉奶匦圆豢赡芡耆恢?,所以有一定的誤差,誤差越小,對(duì)電子元件的一致性要求越高,生產(chǎn)的成本就高了,所以?xún)r(jià)格也就貴一些了。另外,關(guān)于標(biāo)稱(chēng)的電流值,無(wú)論任何電源都有一定的內(nèi)阻,因此當(dāng)電源輸出電流的時(shí)候,會(huì)在內(nèi)部產(chǎn)生壓降,導(dǎo)致兩件事情,一個(gè)是產(chǎn)生熱量,所以電源會(huì)熱,另一個(gè)是導(dǎo)致輸出電壓降低,相當(dāng)于內(nèi)部消耗。”小A:“那都是同樣標(biāo)稱(chēng)電壓的電源,輸出電流不同,能不能用在同一臺(tái)本本上?”大B:“電源電壓一樣,輸出電流不同,能不能用在同一臺(tái)本本上?;镜脑瓌t是大標(biāo)稱(chēng)電流的電源可以代替小標(biāo)稱(chēng)電流的電源。估計(jì)有人會(huì)這樣想,覺(jué)得
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 天津中醫(yī)藥大學(xué)第一附屬醫(yī)院招聘20人備考題庫(kù)及完整答案詳解一套
- 3D打印導(dǎo)板在神經(jīng)外科手術(shù)中的精準(zhǔn)設(shè)計(jì)與精準(zhǔn)定制
- 2025年寧波市升力同創(chuàng)科技咨詢(xún)服務(wù)有限公司招聘?jìng)淇碱}庫(kù)有答案詳解
- 3D打印個(gè)性化骨缺損修復(fù)支架的血管化策略
- 2型糖尿病神經(jīng)病變的早期預(yù)防社區(qū)實(shí)踐
- 上海市2025年事業(yè)單位公開(kāi)招聘高層次急需緊缺專(zhuān)業(yè)技術(shù)人才備考題庫(kù)及完整答案詳解1套
- 2025年韶山旅游發(fā)展集團(tuán)招聘中層管理人員備考題庫(kù)帶答案詳解
- 2025年馬鞍山市住房公積金管理中心編外聘用人員招聘?jìng)淇碱}庫(kù)完整答案詳解
- 核工業(yè)井巷建設(shè)集團(tuán)有限公司2026年校園招聘?jìng)淇碱}庫(kù)及答案詳解參考
- 2025年金華市軌道交通控股集團(tuán)有限公司財(cái)務(wù)崗應(yīng)屆畢業(yè)生招聘?jìng)淇碱}庫(kù)完整參考答案詳解
- 多導(dǎo)睡眠監(jiān)測(cè)課件
- 碼頭岸電設(shè)施建設(shè)技術(shù)規(guī)范
- 統(tǒng)編版(2024新版)七年級(jí)上冊(cè)歷史期末復(fù)習(xí)考點(diǎn)提綱
- 乳腺癌化療藥物不良反應(yīng)及護(hù)理
- 支氣管鏡術(shù)后護(hù)理課件
- 高新技術(shù)產(chǎn)業(yè)園區(qū)建設(shè)項(xiàng)目可行性研究報(bào)告
- 項(xiàng)目HSE組織機(jī)構(gòu)和職責(zé)
- 零基礎(chǔ)AI日語(yǔ)-初階篇智慧樹(shù)知到期末考試答案章節(jié)答案2024年重慶對(duì)外經(jīng)貿(mào)學(xué)院
- MOOC 理論力學(xué)-長(zhǎng)安大學(xué) 中國(guó)大學(xué)慕課答案
- JC∕T 942-2022 丁基橡膠防水密封膠粘帶
- MOOC 工程材料學(xué)-華中科技大學(xué) 中國(guó)大學(xué)慕課答案
評(píng)論
0/150
提交評(píng)論