大B:“我來講講我個(gè)人對(duì)設(shè)計(jì)模式的理解吧?!?
小A:“呵呵!好?。 ?
大B:“也許能讓你更好地理解23種設(shè)計(jì)模式?!?
1、Adapter(適配器)模式:旨在提供用戶期望的接口,以便利用具有不同接口的類的服務(wù)。
(1)個(gè)人理解:實(shí)際上只是把客戶調(diào)用,轉(zhuǎn)變爲(wèi)調(diào)用已經(jīng)存在的方法。適配器的作用可以理解爲(wèi)提供一個(gè)人人皆知的,顧名思義的新方法名。
(2)提示代碼:
publicdoublegetMass(){
returnrocket.getMass(simTime);
}
2、Facade(外觀)模式:旨在爲(wèi)子系統(tǒng)提供一個(gè)接口,使之更加容易使用。
(1)經(jīng)典範(fàn)例:JOptionPane類,JOptionPane.showConfirmDialog(……)
(2)個(gè)人理解:構(gòu)建一個(gè)個(gè)目的明確的類,比如典型的靜態(tài)方法的使用。
(3)提示代碼:
intoption;
option=JOptionPane.showConfirmDialog(……);//靜態(tài)方法創(chuàng)建對(duì)話框
(4)提示關(guān)鍵字:外觀類,工具類,實(shí)例類
3、Composite(組合)模式:旨在讓用戶能夠用統(tǒng)一的接口處理單個(gè)對(duì)象以及對(duì)象組合。
(1)經(jīng)典範(fàn)例:組合,樹,環(huán)
щшш? тTkan? ℃o
(2)個(gè)人理解:其他很多模式的基礎(chǔ),羣組可以包含羣組或者個(gè)體,羣組和個(gè)體有共同的接口。
(3)提示代碼:
MachineComponentmc=(MachineComponent)i.next();
count+=mc.getMachineCount();
(4)提示關(guān)鍵字:遞歸
4、責(zé)任型模式Bridge(橋接)模式:旨在將依賴抽象操作的類與這些抽象操作的實(shí)現(xiàn)相分離,從而使得抽象類與實(shí)現(xiàn)能夠獨(dú)立變化。
(1)經(jīng)典範(fàn)例:驅(qū)動(dòng)程序
(2)個(gè)人理解:將抽象和方法的具體實(shí)現(xiàn)分離,抽象類中包含一個(gè)driver對(duì)象,driver對(duì)象即是對(duì)方法的具體實(shí)現(xiàn)。
(3)提示關(guān)鍵字:裝載
5、ChainofResponsibility(責(zé)任鏈)模式:旨在將一個(gè)方法調(diào)用請(qǐng)求沿著責(zé)任鏈依次轉(zhuǎn)發(fā)給下一個(gè)對(duì)象,讓每個(gè)對(duì)象都有一次機(jī)會(huì)決定自己是否處理該請(qǐng)求,從而降低請(qǐng)求的發(fā)送者與其接受者之間的耦合程度。
(1)個(gè)人理解:尋找責(zé)任的請(qǐng)求在鏈中傳遞,如果責(zé)任人已經(jīng)找到則終止,否則繼續(xù)向其他對(duì)象轉(zhuǎn)發(fā)責(zé)任。
(2)提示代碼:
publicEngineergetResponsible(VisualizationItemitem){
if(iteminstanceoftool){
Toolt=(Tool)item;
returnt.getToolCart().gerResponsible();
}
if(iteminstanceofToolCart){
ToolCarttc=(ToolCart)item;
returntc.gerResponsible();
}
}
(3)提示關(guān)鍵字:轉(zhuǎn)發(fā)
6、Singleton(單例)模式:旨在確保某個(gè)類只有一個(gè)實(shí)例,並且爲(wèi)之提供一個(gè)全局訪問點(diǎn)。
(1)個(gè)人理解:創(chuàng)建一個(gè)類的唯一實(shí)例,可以作爲(wèi)全局變量。
(2)提示代碼:
publicstaticFactorygetFactory(){
if(factory……null)
factory=newFactory();
returnfactory;
}
7、Observer(觀察者)模式:旨在在多個(gè)對(duì)象之間定義一對(duì)多的依賴關(guān)係,以便當(dāng)一個(gè)對(duì)象狀態(tài)改變時(shí),其他所有依賴這個(gè)對(duì)象的對(duì)象都能夠被通知,並自動(dòng)更新。
(1)經(jīng)典範(fàn)例:GUI(MVC中分離M和VC)
(2)個(gè)人理解:當(dāng)一個(gè)對(duì)象發(fā)生改變的時(shí)候,其他關(guān)心該對(duì)象的對(duì)象能夠得到通知,並且更新自身狀態(tài)。
(3)提示代碼:
publicvoidnotifyObservers(){
observers.update();
}
(4)提示關(guān)鍵字:註冊(cè),監(jiān)聽
8、Mediator(中介者)模式:旨在定義一個(gè)對(duì)象來封裝一組對(duì)象之間交互的方式,這樣可避免對(duì)象間的顯示引用,而且還可以獨(dú)立對(duì)這些對(duì)象的交互進(jìn)行修改。
(1)經(jīng)典範(fàn)例:GUI(特指MVC中的controller)
(2)個(gè)人理解:中介者類專門用於處理對(duì)象間的交互,與GUI的佈局組件分離
(3)提示代碼:
publicvoidsetLocation(Machinevalue){
returnmediator.set(this,value);
}
9、Proxy(代理)模式:旨在爲(wèi)某個(gè)對(duì)象提供一個(gè)代理來控制對(duì)該對(duì)象的訪問。
(1)經(jīng)典範(fàn)例:圖像代理(長(zhǎng)時(shí)間載入內(nèi)存前的Loading提示)
(2)個(gè)人理解:提供一個(gè)代理來承擔(dān)責(zé)任(轉(zhuǎn)發(fā)請(qǐng)求),實(shí)際操作的對(duì)象並不是根本對(duì)象,而是一個(gè)用戶和真正實(shí)現(xiàn)之間的中間角色。
(3)提示代碼:
setImage(LOADING.getImage());
callbackFrame.repaint();
newThread(this).start();
(4)提示關(guān)鍵字:佔(zhàn)位
10、Flyweight(享元)模式:旨在通過共享來爲(wèi)大量的細(xì)粒度對(duì)象提供有效的支持。
(1)個(gè)人理解:很多類具有相同的且不變的屬性,可以將這些屬性提取出來構(gòu)成享元,在一個(gè)特定的工廠類中作爲(wèi)內(nèi)部類,具有static的get方法,便於外部類共享。
(2)提示代碼:
publicclassChemicalFactory{
privatestaticMaochemicals=newHashMap();
ChemicalImp{
//someattributesandmethods
}
static{
chemicals.put(newChemicalImp());
}
publicstaticChemicalgetChemical(Stringname){
return***;
}
}
(3)提示關(guān)鍵字:共享對(duì)象
11、Builder(生成器)模式:旨在把構(gòu)造對(duì)象實(shí)例的代碼邏輯移到要實(shí)例化的類的外部,以便於細(xì)化構(gòu)造過程,或者簡(jiǎn)化對(duì)象。
(1)經(jīng)典範(fàn)例:解析文本構(gòu)造對(duì)象
(2)個(gè)人理解:用一個(gè)builder類收集構(gòu)造信息,在確定信息足夠(或者滿足構(gòu)造的最低要求)的時(shí)候,再生成對(duì)象。
(3)提示代碼:
Stringsample=“*****”;
ReservationBuliderbuilder=newUnforgivingBuilder();
newReservationParser(builder).parse(sample);
Resercationres=builder.build();
(4)提示關(guān)鍵字:逐步構(gòu)造
12、FactoryMethod(工廠方法)模式:旨在定義一個(gè)用於創(chuàng)建對(duì)象的接口,同時(shí)控制對(duì)哪個(gè)類進(jìn)行實(shí)例化。
(1)經(jīng)典範(fàn)例:迭代器
(2)個(gè)人理解:爲(wèi)相關(guān)的多個(gè)類提供一個(gè)共同的接口,客戶不需要知道該實(shí)例化哪個(gè)類,具體實(shí)例化的類由服務(wù)的提供者決定。
(3)提示代碼:
Listlist=Arrays.asList(newString[]{“1”,“2”,“3”});
Iteratoriter=list.iterator();
(4)提示關(guān)鍵字:共同接口
13、AbstractFactory(抽象工廠)模式:旨在創(chuàng)建一系列相互關(guān)聯(lián)或相互依賴的對(duì)象。
(1)經(jīng)典範(fàn)例:GUI工具包
(2)個(gè)人理解:創(chuàng)建一系列相關(guān)的對(duì)象,也就是把創(chuàng)建一個(gè)大對(duì)象所需要的子操作聚合起來。
(3)提示代碼:
publicJButtoncreateButtonOK(){
JButtonb=super.createButtonOk();
b.setIcon(getIcon(“images/123.gif”));
returnb;
}
(4)提示關(guān)鍵字:外觀和感覺
14、Prototype(原型)模式:通過拷貝一個(gè)現(xiàn)有對(duì)象生成新的對(duì)象。
(1)個(gè)人理解:通過複製一個(gè)已經(jīng)存在的對(duì)象,保存原來對(duì)象的狀態(tài),在此基礎(chǔ)上進(jìn)行進(jìn)一步的改動(dòng)。
(2)提示代碼:
publicOzPanelcopy2(){
OzPanelresult=newOzPanel();
result.setBackground(this.getBackground());
//moreresult.set***methods……
returnresult;
}
(3)提示關(guān)鍵字:複製
15、Memento(備忘錄)模式:旨在爲(wèi)對(duì)象提供狀態(tài)存儲(chǔ)和狀態(tài)恢復(fù)功能。
(1)經(jīng)典範(fàn)例:撤銷操作
(2)個(gè)人理解:使用棧進(jìn)行撤銷和恢復(fù)的操作,棧頂部是當(dāng)前的狀態(tài)。更多的,可以把相關(guān)狀態(tài)進(jìn)行持久性存儲(chǔ)。
(3)提示代碼:
publicvoidundo(){
if(!canUndo())return;
mementos.pop();
}
(4)提示關(guān)鍵字:redo,undo
16、TemplateMethod(模板方法)模式:旨在一個(gè)方法中實(shí)現(xiàn)一個(gè)算法,並遵循算法中某些步驟的定義,從而使得其他類可以重新定義這些新步驟。
(1)經(jīng)典範(fàn)例:(根據(jù)不同規(guī)則)排序
(2)個(gè)人理解:在算法的實(shí)現(xiàn)中,把一些需要自定義的部分(通常是算法的核心部分),留在外部的類來實(shí)現(xiàn)。並可以需要實(shí)現(xiàn)的部分設(shè)置鉤子。
(3)提示代碼:
Array.sout(rockets,newApogeeComparator());
publicclassApogeeComparatorimplementsComparator{
//basemethodaboutsort……
}
(4)提示關(guān)鍵字:算法框架+算法步驟
17、State(狀態(tài))模式:旨在將與狀態(tài)有關(guān)的處理邏輯分散到代表狀態(tài)的各個(gè)類中。
(1)個(gè)人理解:將所有的狀態(tài)都構(gòu)建成一個(gè)相應(yīng)的類,它們的超類對(duì)外部各個(gè)事件提供相應(yīng)的同意接口,使得調(diào)用者無需判斷當(dāng)前狀態(tài)。
(2)提示代碼:
publicclassDoor2extendsObservable{
publicvoidtouch(){
state.touch();
}
}
publicclassDoorOpenextendsDoorState{
publicvoidtouch(){
door.setState(door.STAYOPEN);
}
}
(3)提示關(guān)鍵字:狀態(tài)處理分散
18、Strategy(策略)模式:旨在把可選的策略或方案封裝到不同的類中,並在這些類中實(shí)現(xiàn)一個(gè)共同的操作。
(1)個(gè)人理解:爲(wèi)不同的解決方案建立類,在執(zhí)行的時(shí)候選擇一個(gè)策略執(zhí)行。與State模式比較,兩者很接近,前者傾向在可選的方案中選擇,後者是在不同的狀態(tài)之間遷移。
(2)提示代碼:
privateAdvisorgetAdvisor(){
if(advisor……null){
if(promotionAdvisor.hasItem())
advisor=promotionAdvisor;
//maybemoreelseif
}
returnadvisor;
}
(3)提示關(guān)鍵字:策略選擇+策略執(zhí)行
19、Command(命令)模式:旨在將請(qǐng)求封裝爲(wèi)一個(gè)對(duì)象,並將該請(qǐng)求對(duì)象作爲(wèi)參數(shù);客戶可以提供不同的請(qǐng)求對(duì)象,如隊(duì)列請(qǐng)求,時(shí)間請(qǐng)求或者日誌請(qǐng)求;也可以讓客戶準(zhǔn)備調(diào)用該請(qǐng)求的特定上下文。
(1)經(jīng)典範(fàn)例:菜單命令(actionPerformed())
(2)個(gè)人理解:將方法(一般是execute()方法)封裝在對(duì)象中,使用時(shí)直接調(diào)用相關(guān)mand對(duì)象的execute()方法即可??梢宰鳡?wèi)Template模式的替代模式。
(3)提示代碼:
Commanddoze=newCommand(){
publicvoidexecute(){
//dosomething
}
}
publicclassCommandTimer{
Publicstaticlongtime(Commandmand){
mand.execute();
}
}
longactual=CommandTimer.time(doze);
(4)提示關(guān)鍵字:封裝對(duì)象
20、Interpreter(解釋器)模式:旨在使開發(fā)者可以根據(jù)自己定義的組合規(guī)則生成可執(zhí)行的對(duì)象。
(1)個(gè)人理解:常與Command和Composite模式配合使用,對(duì)命令進(jìn)行組合使用,有點(diǎn)像編程中使用語句構(gòu)造功能。
(2)提示代碼:
publicclassIfCommandextendsCommand{
protectedTermterm;
protectedCommandbody;
protectedCommandelseBody;
publicIfCommand(Termterm,Commandbody,CommandelseBody){
this.term=term;
this.body=body;
this.elseBody=elseBody;
}
publicvoidexecute(){
if(term.eval()!=null)
body.execyte();
else
elseBody.execute();
}
}
(3)提示關(guān)鍵字:解釋器,組合對(duì)象
21、Decorator(裝飾器)模式:旨在使開發(fā)者能夠動(dòng)態(tài)地組織對(duì)象的行爲(wèi)。
(1)經(jīng)典範(fàn)例:流和輸出器,函數(shù)包裝器
(2)個(gè)人理解:在運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建不同的變化
(3)提示代碼:
BufferedOutputStreamout=
newBufferedOutputStream(
newGZIPOutputStream(
newFileOutputStream(args[1])));
(4)提示關(guān)鍵字:動(dòng)態(tài)組合
22、Iterator(迭代器)模式:旨在爲(wèi)開發(fā)人員提供一種順序訪問集合元素的方法。
(1)個(gè)人理解:在新建一個(gè)結(jié)構(gòu)的時(shí)候,爲(wèi)順序訪問其元素,可以同樣新建一個(gè)對(duì)應(yīng)的迭代器類。也可以自定義訪問元素的其他方式(比如逆序)。
(2)提示代碼:
Listemployees;
ListIteratorforward(employees);
ReverseListIteratorbackward(employees);
PrintEmployees(forward);
PrintEmployees(backward);
(3)提示關(guān)鍵字:訪問元素
23、Visitor(訪問者)模式:旨在讓開發(fā)者能夠在不修改現(xiàn)有類層次結(jié)構(gòu)的前提下擴(kuò)展該類層次結(jié)構(gòu)的行爲(wèi)。
(1)個(gè)人理解:在開發(fā)類的時(shí)候,留有一個(gè)accept()操作,該操作接受一個(gè)visitor參數(shù)。在需要爲(wèi)類增加新的操作時(shí),無需改變?cè)瓉淼念悓哟?,直接編輯visitor中的visit操作,然後使用accept()方法接受即可。
(2)提示代碼:
publicclassFindVisitorimplementsMachineVisitor{
publicMachineComponetfind(MachineComponetmc){
mc.accept(this);
}
publicvoidvisit(MachineCompositemc){
//dosomething
}
}
MachineComponentfactory=OozinozFactory.dublin();
MachineComponentmachine=newFindVisitor().find(factory,3404);
(3)提示關(guān)鍵字:不改變類層次附錄:面向?qū)ο蠡A(chǔ)
小A:“爲(wèi)什麼要‘面向?qū)ο蟆???
大B:“面向?qū)ο蠓椒ㄊ箻?gòu)建系統(tǒng)更容易,因爲(wèi):解決正確的問題,正常工作,易維護(hù),易擴(kuò)充,易重用。大家發(fā)現(xiàn)面向?qū)ο蟾桌斫?,?shí)現(xiàn)可以更簡(jiǎn)單。把數(shù)據(jù)和功能組合在一起簡(jiǎn)單而自然,分析和實(shí)現(xiàn)之間的概念跨度更小,設(shè)計(jì)良好的一組對(duì)象能彈性地適應(yīng)重用和變化,可視化模型提供更有效的溝通,建模過程有助於創(chuàng)建通用詞彙以及在開發(fā)者和用戶/客戶之間達(dá)成共識(shí)。非計(jì)算機(jī)編程人員也能理解對(duì)象模型,這些好處可以使用面向?qū)ο蠓椒ǐ@得,但面向?qū)ο蠓椒ú荒鼙WC這一點(diǎn)?!?
小A:“怎樣才能變成優(yōu)秀的面向?qū)ο笤O(shè)計(jì)者?”
大B:“只有靠經(jīng)驗(yàn)和聰明的頭腦才能做到?!?
過程化方法(TheProceduralApproach)
小A:“怎樣過程化方法?”
大B:“系統(tǒng)由過程(procedures)組成,過程之間互相發(fā)送數(shù)據(jù),過程和數(shù)據(jù)各自獨(dú)立,集中於數(shù)據(jù)結(jié)構(gòu)、算法和運(yùn)算步驟的先後順序,過程經(jīng)常難以重用,缺乏具有較強(qiáng)表現(xiàn)力的可視化建模技術(shù),分析與實(shí)現(xiàn)之間需要進(jìn)行概念轉(zhuǎn)換,本質(zhì)上是機(jī)器/彙編語言的抽象,從設(shè)計(jì)模型到代碼實(shí)現(xiàn)跨度很大。”
面向?qū)ο蠓椒?
大B:“系統(tǒng)由對(duì)象組成,對(duì)象互相發(fā)送消息(過程調(diào)用)相關(guān)的數(shù)據(jù)和行爲(wèi)緊密地綁定在對(duì)象中,把問題領(lǐng)域建模成對(duì)象,要解決的問題自然的映射爲(wèi)代碼的實(shí)現(xiàn),可視模型表現(xiàn)力強(qiáng),相對(duì)容易理解,集中於實(shí)現(xiàn)之前所確定的職責(zé)(responsibilities)和接口。強(qiáng)有力的概念:接口,抽象,封裝,繼承,委託(delegation)和多態(tài)。問題的可視模型逐漸進(jìn)化成解決方案模型,設(shè)計(jì)模型與代碼實(shí)現(xiàn)之間跨度較小努力縮減軟件的複雜度?!?
溫度換算
大B:“下面我就以溫度換算爲(wèi)例?!?
過程/函數(shù)化方法
floatc=getTemperature();//假定爲(wèi)攝氏度。
floatf=toFarenheitFromCelcius(c);
floatk=toKelvinFromCelcius(c);
floatx=toKelvinFromFarenheit(f);
floaty=toFarenheitFromKelvin(k);
面向?qū)ο蠓椒?
Temptemp=getTemperature();
floatc=temp.toCelcius();
floatf=temp.toFarenheit(); ωωω¤Tтkan¤¢O
floatk=temp.toKelvin();
包含有數(shù)據(jù)的Temp的內(nèi)部單元是什麼?
建模(Modeling)
小A:“成功的程序能解決真實(shí)世界的問題?!?
大B:“嗯,是的。它們緊密對(duì)應(yīng)於需要解決的問題。對(duì)問題領(lǐng)域和用戶活動(dòng)進(jìn)行建模?!?
小A:“建模促進(jìn)與用戶更好的可視化交流?!?
大B:“成功的面向?qū)ο笤O(shè)計(jì)總是一開始就由領(lǐng)域?qū)<液蛙浖O(shè)計(jì)者建立一個(gè)反映問題領(lǐng)域的可視化的‘對(duì)象模型’?!?
小A:“嗯。是的?!?
大B:“你願(yuàn)意讓承包人在沒有設(shè)計(jì)藍(lán)圖的情況下建造你的新房子嗎?”
小A:“那當(dāng)然不行啦?!?
對(duì)象
大B:“你知道怎樣去理解什麼是對(duì)象嗎?”
小A:“對(duì)象代表真實(shí)或抽象的事物,有一個(gè)名字,有明確的職責(zé)(well-definedresponsibilities),展示良好的行爲(wèi)(well-definedbehavior),接口清晰,並且儘可能簡(jiǎn)單、自相容,內(nèi)聚,完備(self-consistent,coherent,andplete)。”
大B:“嗯,對(duì)。(通常)不是很複雜或很大,只需要理解自己和一小部分其他對(duì)象的接口,與一小部分其它對(duì)象協(xié)同工作(teamplayers),儘可能地與其它對(duì)象鬆散耦合(looselycoupled),很好地文檔化,以便他人使用或重用,對(duì)象是類的實(shí)例,每一個(gè)對(duì)象都有唯一的標(biāo)識(shí),類定義一組對(duì)象的接口和實(shí)現(xiàn),即定義了這些對(duì)象的行爲(wèi),抽象類不能擁有實(shí)例,只要有抽象類(如寵物),通常就會(huì)有能夠?qū)嵗木唧w類(如貓,狗等),一些面嚮對(duì)象語言(如Smalltalk)支持元類(metaclass)的概念,程序員可以隨時(shí)(on-the-fly)定義一個(gè)類,然後實(shí)例化。這種情況下,類也是一個(gè)對(duì)象,即元類。對(duì)象一旦實(shí)例化,就不能更改它的類?!?
對(duì)象的特徵
大B:“那你知道對(duì)象有什麼特徵嗎?”
小A:“有唯一標(biāo)識(shí),可以分成許多種類(即類),可以繼承或聚合。行爲(wèi)、職責(zé)明確,接口與實(shí)現(xiàn)分離,隱藏內(nèi)部結(jié)構(gòu),有不同的狀態(tài),可以提供服務(wù),可以給其它對(duì)象發(fā)送消息,從其它對(duì)象接收消息,並做出相應(yīng)響應(yīng),可以把職責(zé)委託給其它對(duì)象。”
大B:“對(duì),說得非常全面?!?
類
小A:“怎麼樣才叫類呢?”
大B:“有公共的屬性和行爲(wèi)的一組對(duì)象可以抽象成爲(wèi)類,對(duì)象通常根據(jù)你所感興趣的屬性而分類?!?
小A:“喔?!?
大B:“例如:街道,馬路,高速公路……不同的程序?qū)λ鼈兎诸愐膊煌?。交通模擬器程序,單行道,雙通道,有分車道的,住宅區(qū)的,限制通行的維護(hù)調(diào)度程序,路面材料,重型卡車運(yùn)輸類本身也可以有屬性和行爲(wèi)。例如:養(yǎng)老金管理程序中的‘僱員’類僱員總數(shù),僱員編制多少,不同語言對(duì)類的支持略有不同:Smalltalk把類當(dāng)作對(duì)象(很有好處),C++提供最小限度的支持(有時(shí)會(huì)帶來很多煩惱),Java位於上述兩者之間,類也是對(duì)象,類可以有屬性‘僱員’類可以有一個(gè)包含其所有實(shí)例的列表(list)‘彩票’類可以有一個(gè)種子(seed)用於產(chǎn)生隨機(jī)票號(hào),該種子被所有實(shí)例共享,類可以有行爲(wèi),僱員”類可以有g(shù)etEmployeeBySerialNum行爲(wèi)?!势薄惪梢杂術(shù)enerateRandomNumber行爲(wèi)。
封裝
大B:“只暴露相關(guān)的細(xì)節(jié),即公有接口(publicinterface)?!?
小A:“封裝什麼?如何封裝?”
大B:“隱藏‘齒輪和控制桿’只暴露客戶需要的職責(zé),防止對(duì)象受到外界干擾,防止其它對(duì)象依賴可能變化的細(xì)節(jié),信息隱藏有助於對(duì)象和模塊之間的鬆散耦合,使得設(shè)計(jì)更加靈活,更易於重用,減少代碼之間的依賴,‘有好籬笆纔有好鄰居’。例如:汽車的氣動(dòng)踏板。”
小A:“怎樣才能更好地實(shí)踐?”
大B:“最佳實(shí)踐:對(duì)象之間只通過方法(函數(shù))互相訪問。切忌直接訪問屬性?!?
classPerson{
publicintage;
}
classBetterPerson{
privateintage;//changetodateOfBirth
publicintgetAge(){returnage;}
}
更完善的Person類可能是:privatedateOfBirth
抽象
小A:“什麼是抽象?”
大B:“抽象使得泛化(generalizaions)成爲(wèi)可能,簡(jiǎn)化問題-忽略複雜的細(xì)節(jié),關(guān)注共性,並且允許變更,人類經(jīng)常使用泛化。當(dāng)你看見約翰和簡(jiǎn)家裡的那頭灰德國(guó)牧羊犬時(shí),你有沒有……想到‘狗’這個(gè)詞?抽象同樣能簡(jiǎn)化計(jì)算機(jī)程序。例如,軟件中有兩個(gè)重要抽象:客戶端和服務(wù)器(clientsandservers)。”
小A:“喔?!?
大B:“在圖形用戶界面中,系統(tǒng)可能會(huì)詢問用戶各種問題:是或不是多選一?輸入數(shù)字,任意文本問題統(tǒng)一處理這些問題會(huì)顯得很簡(jiǎn)單,每一個(gè)問題都作爲(wèi)Question類的特例(specialization);程序只需維護(hù)這些問題的實(shí)例列表,分別調(diào)用各自的askTheUser()方法。”
繼承
小A:“什麼是繼承?”
大B:“繼承用於描述一個(gè)類與其它類的不同之處。例如:類Y像類X,但有下列不同……”
小A:“爲(wèi)什麼使用繼承?”
大B:“你有兩種類型,其中一種是另一種的擴(kuò)展。有時(shí)(不是所有時(shí)候)你想忽略對(duì)象之間的不同,而只關(guān)注它們的共同之處(基類)。這就是泛化。假如某系統(tǒng)需要對(duì)不同的形狀進(jìn)行操作(經(jīng)典例子):有時(shí)你並不關(guān)心你正在操作的形狀的種類(例如,移動(dòng)形狀時(shí))有時(shí)你必須知道形狀的種類(在顯示器上繪製形狀)”
小A:“怎樣去理解派生類?”
大B:“派生類繼承自基類;派生類擴(kuò)展了基類;派生類是基類的特殊化(specialization)。派生類能夠提供額外的狀態(tài)(數(shù)據(jù)成員),或額外的行爲(wèi)(成員函數(shù)/方法),或覆蓋所繼承的方法。基類是所有它的派生類的泛化。如:通常所有寵物都有名字。基類(BaseClass)=父類(parentclass)=超類(superclass)派生類(DerivedClass)=子類(childclass)=子類(subclass)”
小A:“喔?!?
大B:“繼承含有(有些,不是全部)是一個(gè)(is-a)或是一種(is-a-kind-of)的關(guān)係,正方形是一種矩形(使用繼承),Leroy是一種狗(不使用繼承),傳統(tǒng)的過程分析和設(shè)計(jì)中不能很好地模擬這種關(guān)係。繼承是一種強(qiáng)有力的機(jī)制,使我們關(guān)注共性,而不是特定的細(xì)節(jié)。使得代碼可以重用且富有彈性(能適應(yīng)變化)?!?
小A:怎樣去實(shí)現(xiàn)繼承?
大B:“實(shí)現(xiàn)繼承(Implementationinheritance):派生類繼承基類的屬性和行爲(wèi)。”
小A:“又應(yīng)該怎樣去接口繼承?”
大B:“接口繼承(Interfaceinheritance):類實(shí)現(xiàn)抽象接口的方法,保留既定語義(intendedsemantics)C++允許多重實(shí)現(xiàn)繼承。Java規(guī)定派生類只能有一個(gè)基類,但可以繼承自多個(gè)接口。”
多態(tài)
小A:“什麼是多態(tài)?”
大B:“多態(tài)是一種允許多個(gè)類針對(duì)同一消息有不同的反應(yīng)的能力。對(duì)於任何實(shí)現(xiàn)了給定接口的對(duì)象,在不明確指定類名的情況下,就可以使用。例如:question.askTheUser();當(dāng)然,這些不同反應(yīng)都有類似的本質(zhì)儘可能使用接口繼承和動(dòng)態(tài)(運(yùn)行期)綁定Liskov替換原則:如果Y是X的子類,那麼在任何使用X實(shí)例的地方都可以用Y的實(shí)例來替換。”
演示多態(tài)的Java代碼
//File:question/QuestionTest.java
//下面的代碼將輸出什麼?
//RefertotheBeginningJavalinkonthecoursewebsite.
packagequestion;
abstractclassQuestion{//Fullclassnameisquestion.QuestionTest
publicQuestion(Stringtext){//Constructor
theText=text;
}
publicabstractvoidaskTheUser();
protectedStringtheText;
}
classYesNoQuestionextendsQuestion{
publicYesNoQuestion(Stringtext){super(text);}
publicvoidaskTheUser(){
System.out.println(theText);
System.out.println(“YESorNO……?”);
}
}
classFreeTextQuestionextendsQuestion{
publicFreeTextQuestion(Stringtext){super(text);}
publicvoidaskTheUser(){
System.out.println(theText);
System.out.println(“Well……?Whatstheanswer……?”);
}
}
publicclassQuestionTest{
publicstaticvoidmain(String[]args){
Question[]questions=getQuestions();
for(inti=0;i