設(shè)計模式問題_第1頁
設(shè)計模式問題_第2頁
設(shè)計模式問題_第3頁
設(shè)計模式問題_第4頁
設(shè)計模式問題_第5頁
已閱讀5頁,還剩34頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

設(shè)計模式遵循的原則有6個:1、開閉原則(OpenClosePrinciple)對擴展開放,對修改關(guān)閉。2、 里氏代換原則(LiskovSubstitutionPrinciple)只有當(dāng)衍生類可以替換掉基類,軟件單位的功能不受到影響時,基類才能真正被復(fù)用,而衍生類也能夠在基類的基礎(chǔ)上增加新的行為。3、 依賴倒轉(zhuǎn)原貝U(DependenceInversionPrinciple)這個是開閉原則的基礎(chǔ),對接口編程,依賴于抽象而不依賴于具體。4、 接口隔離原則(InterfaceSegregationPrinciple)使用多個隔離的借口來降低耦合度。5、迪米特法則(最少知道原則)(DemeterPrinciple)一個實體應(yīng)當(dāng)盡量少的與其他實體之間發(fā)生相互作用,使得系統(tǒng)功能模塊相對獨立。6、 合成復(fù)用原則(CompositeReusePrinciple)原則是盡量使用合成/聚合的方式,而不是使用繼承。繼承實際上破壞了類的封裝性,超類的方法可能會被子類修改Num1:單例模式單例模式的關(guān)鍵有兩點:1、 構(gòu)造方法為私有,這樣外界就不能隨意調(diào)用。2、 get的方法為靜態(tài),由類直接調(diào)用多例模式(Multiton)1、 多例類可以有多個實例2、 多例類必須能夠自我創(chuàng)建并管理自己的實例,并向外界提供自己的實例。一、單例模式和多例模式說明:單例模式和多例模式屬于對象模式。單例模式的對象在整個系統(tǒng)中只有一份,多例模式可以有多個實例。它們都不對外提供構(gòu)造方法,即構(gòu)造方法都為私有。單例和多例的詳細描述:1.什么是單例多例:所謂單例就是所有的請求都用一個對象來處理,比如我們常用的service和dao層的對象通常都是單例的,而多例則指每個請求用一個新的對象來處理,比如action;

如何產(chǎn)生單例多例:在通用的SSH中,單例在spring中是默認的,如果要產(chǎn)生多例,則在配置文件的bean中添力口scope=”prototype”;為什么用單例多例:之所以用單例,是因為沒必要每個請求都新建一個對象,這樣子既浪費CPU又浪費內(nèi)存;之所以用多例,是為了防止并發(fā)問題;即一個請求改變了對象的狀態(tài),此時對象又處理另一個請求,而之前請求對對象狀態(tài)的改變導(dǎo)致了對象對另一個請求做了錯誤的處理;用單例和多例的標準只有一個:當(dāng)對象含有可改變的狀態(tài)時(更精確的說就是在實際應(yīng)用中該狀態(tài)會改變),則多例,否則單例;何時用單例?何時用多例?對于struts2來說,action必須用多例,因為action本身含有請求參數(shù)的值,即可改變的狀態(tài);而對于STRUTS1來說,action則可用單例,因為請求參數(shù)的值是放在actionForm中,而非action中的;另外要說一下,并不是說service或dao一定是單例,標準同第3點所講的,就曾見過有的service中也包含了可改變的狀態(tài),同時執(zhí)行方法也依賴該狀態(tài),但一樣用的單例,這樣就會出現(xiàn)隱藏的BUG,而并發(fā)的BUG通常很難重現(xiàn)和查找;單例的寫法第一種(懶漢,線程不安全):publicclassSingleton{privatestaticSingletoninstanee;privateSingleton(){}publicstaticSingletongetInstance(){if(instanee==null){instanee=newSingleton();}returninstanee;}}這種寫法lazyloading很明顯,但是致命的是在多線程不能正常工作。第二種(懶漢,線程安全):publicclassSingleton{privatestaticSingletoninstanee;

privateSingleton(){}publicstaticsynchronizedSingletongetInstance(){if(instanee==null){instanee=newSingleton();}returninstanee;}}這種寫法能夠在多線程中很好的工作,而且看起來它也具備很好的lazyloading,但是,遺憾的是,效率很低,99%情況下不需要同步。第三種(餓漢):publicclassSingleton{privatestaticSingletoninstanee=newSingleton();privateSingleton(){}publicstaticSingletongetInstance(){returninstanee;}}這種方式基于classloder機制避免了多線程的同步問題,不過,instanee在類裝載時就實例化,雖然導(dǎo)致類裝載的原因有很多種,在單例模式中大多數(shù)都是調(diào)用getlnstanee方法,但是也不能確定有其他的方式(或者其他的靜態(tài)方法)導(dǎo)致類裝載,這時候初始化instanee顯然沒有達到lazyloading的效果。第四種(餓漢,變種):publicclassSingleton{privateSingletoninstanee=null;static{instanee=newSingleton();}privateSingleton(){}publicstaticSingletongetInstance(){returnthis.instanee;

}表面上看起來差別挺大,其實更第三種方式差不多,都是在類初始化即實例化instanee。第五種(靜態(tài)內(nèi)部類):publicclassSingleton{privatestaticclassSingletonHolder{privatestaticfinalSingletonINSTANCE=newSingleton();}privateSingleton(){}publicstaticfinalSingletongetInstance(){returnSingletonHolder.INSTANCE;}}這種方式同樣利用了classloder的機制來保證初始化instanee時只有一個線程,它跟第三種和第四種方式不同的是(很細微的差別):第三種和第四種方式是只要Singleton類被裝載了,那么instanee就會被實例化(沒有達到lazyloading效果),而這種方式是Singleton類被裝載了,instanee不一定被初始化。因為SingletonHolder類沒有被主動使用,只有顯示通過調(diào)用getlnstanee方法時,才會顯示裝載SingletonHolder類,從而實例化instance。想象一下,如果實例化instanee很消耗資源,我想讓他延遲加載,另外一方面,我不希望在Singleton類加載時就實例化,因為我不能確保Singleton類還可能在其他的地方被主動使用從而被加載,那么這個時候?qū)嵗痠nstanee顯然是不合適的。這個時候,這種方式相比第三和第四種方式就顯得很合理。Num2:工廠模式基本概念:為創(chuàng)建對象提供過渡接口,以便將創(chuàng)建對象的具體過程屏蔽隔離起來,達到提高靈活性的目的。分為三類:?簡單工廠模式SimpleFactory:不利于產(chǎn)生系列產(chǎn)品;?工廠方法模式FactoryMethod:又稱為多形性工廠;?抽象工廠模式AbstractFactory:又稱為工具箱,產(chǎn)生產(chǎn)品族,但不利于產(chǎn)生新的產(chǎn)品;這三種模式從上到下逐步抽象,并且更具一般性。GOF在《設(shè)計模式》一書中將工廠模式分為兩類:工廠方法模式(FactoryMethod)與抽象工廠模式(AbstractFactory)。將簡單工廠模式(SimpleFactory)看為工廠方法模式的一種特例,兩者歸為一類。簡單工廠模式

簡單工廠模式又稱靜態(tài)工廠方法模式。重命名上就可以看出這個模式一定很簡單。它存在的目的很簡單:定義一個用于創(chuàng)建對象的接口。在簡單工廠模式中,一個工廠類處于對產(chǎn)品類實例化調(diào)用的中心位置上,它決定那一個產(chǎn)品類應(yīng)當(dāng)被實例化,如同一個交通警察站在來往的車輛流中,決定放行那一個方向的車輛向那一個方向流動一樣。先來看看它的組成:工廠類角色:這是本模式的核心,含有一定的商業(yè)邏輯和判斷邏輯。在java中它往往由一個具體類實現(xiàn)。抽象產(chǎn)品角色:它一般是具體產(chǎn)品繼承的父類或者實現(xiàn)的接口。在java中由接口或者抽象類來實現(xiàn)。具體產(chǎn)品角色:工廠類所創(chuàng)建的對象就是此角色的實例。在java中由一個具體類實現(xiàn)。示例代碼:publicclassFactory{//getClass產(chǎn)生Sample一般可使用動態(tài)類裝載裝入類。publicstaticSamplecreator(intwhich){if(which==1)returnnewSampleA();elseif(which==2)returnnewSampleB();}}還有一種目前比較流行的規(guī)范是把靜態(tài)工廠方法命名為valueOf或者getInstance。valueOf:該方法返回的實例與它的參數(shù)具有同樣的值,例如:Integera=Integer.valueOf(lOO);//返回取值為100的Integer對象publicclassComplex{privatefinalfloatre;privatefinalfloatim;privateComplex(floatre,floatim){this.re=re;

this.im=im;publicstaticComplexvalueOf(floatre,floatim){returnnewComplex(re,im);}publicstaticComplexvalueOfPolar(floatr,floattheta){returnnewComplex((float)(r*Math.cos(theta)),(float)(r*Math.sin(theta)));}}從上面代碼可以看出,valueOf()方法能執(zhí)行類型轉(zhuǎn)換操作,在本例中,把int類型的基本數(shù)據(jù)轉(zhuǎn)換為Integer對象。getInstance:返回的實例與參數(shù)匹配,例如:Calendarcal二Calendar.getInstance(Locale.CHINA);//返回符合中國標準的日歷工廠方法模式工廠方法模式是簡單工廠模式的進一步抽象化和推廣,工廠方法模式里不再只由一個工廠類決定那一個產(chǎn)品類應(yīng)當(dāng)被實例化,這個決定被交給抽象工廠的子類去做。來看下它的組成:抽象工廠角色:這是工廠方法模式的核心,它與應(yīng)用程序無關(guān)。是具體工廠角色必須實現(xiàn)的接口或者必須繼承的父類。在java中它由抽象類或者接口來實現(xiàn)。具體工廠角色:它含有和具體業(yè)務(wù)邏輯有關(guān)的代碼。由應(yīng)用程序調(diào)用以創(chuàng)建對應(yīng)的具體產(chǎn)品的對象抽象產(chǎn)品角色:它是具體產(chǎn)品繼承的父類或者是實現(xiàn)的接口。在java中一般有抽象類或者接口來實現(xiàn)。具體產(chǎn)品角色:具體工廠角色所創(chuàng)建的對象就是此角色的實例。在java中由具體的類來實現(xiàn)。工廠方法模式使用繼承自抽象工廠角色的多個子類來代替簡單工廠模式中的''上帝類〃。正如上面所說,這樣便分擔(dān)了對象承受的壓力;而且這樣使得結(jié)構(gòu)變得靈活起來一一當(dāng)有新的產(chǎn)品(即暴發(fā)戶的汽車)產(chǎn)生時,只要按照抽象產(chǎn)品角色、抽象工廠角色提供的合同來生成,那么就可以被客戶使用,而不必去修改任何已有的代碼??梢钥闯龉S角色的結(jié)構(gòu)也是符合開閉原則的!示例代碼:

//抽象產(chǎn)品角色publicinterfaceMoveable{voidrun();}//具體產(chǎn)品角色publicclassPlaneimplementsMoveable{@Overridepublicvoidrun(){System.out.println("plane....");}}//具體產(chǎn)品角色publicclassBroomimplementsMoveable{@Overridepublicvoidrun(){System.out.println("broom ");}}//抽象工廠publicabstractclassVehicleFactory{abstractMoveablecreate();}//具體工廠

publicclassPlaneFactoryextendsVehicleFactory{publicMoveablecreate(){returnnewPlane();}}//具體工廠publicclassBroomFactoryextendsVehicleFactory{publicMoveablecreate(){returnnewBroom();}}//測試類publicclassTest{publicstaticvoidmain(String[]args){VehicleFactoryfactory=newBroomFactory();Moveablem=factory.create();m.run();}}可以看出工廠方法的加入,使得對象的數(shù)量成倍增長。當(dāng)產(chǎn)品種類非常多時,會出現(xiàn)大量的與之對應(yīng)的工廠對象,這不是我們所希望的。因為如果不能避免這種情況,可以考慮使用簡單工廠模式與工廠方法模式相結(jié)合的方式來減少工廠類:即對于產(chǎn)品樹上類似的種類(一般是樹的葉子中互為兄弟的)使用簡單工廠模式來實現(xiàn)。簡單工廠和工廠方法模式的比較工廠方法模式和簡單工廠模式在定義上的不同是很明顯的。工廠方法模式的核心是一個抽象工廠類,而不像簡單工廠模式,把核心放在一個實類上。工廠方法模式可以允許很多實的工廠類從抽象工廠類繼承下來,從而可以在實際上成為多個簡單工廠模式的綜合,從而推廣了簡單工廠模

式。反過來講,簡單工廠模式是由工廠方法模式退化而來。設(shè)想如果我們非常確定一個系統(tǒng)只需要一個實的工廠類,那么就不妨把抽象工廠類合并到實的工廠類中去。而這樣一來,我們就退化到簡單工廠模式了。抽象工廠模式示例代碼://抽象工廠類publicabstractclassAbstractFactory{publicabstractVehiclecreateVehicle();publicabstractWeaponcreateWeapon();publicabstractFoodcreateFood();}//具體工廠類,其中Food,Vehicle,Weapon是抽象類,publicclassDefaultFactoryextendsAbstractFactory{@OverridepublicFoodcreateFood(){returnnewApple();}@OverridepublicVehiclecreateVehicle(){returnnewCar();}@OverridepublicWeaponcreateWeapon(){returnnewAK47();

//測試類publicclassTest{publicstaticvoidmain(String[]args){AbstractFactoryf=newDefaultFactory();Vehiclev=f.createVehicle();run();Weaponw=f.createWeapon();w. shoot();Fooda=f.createFood();a.printName();}}在抽象工廠模式中,抽象產(chǎn)品(Abstractproduct)可能是一個或多個,從而構(gòu)成一個或多個產(chǎn)品族(ProductFamily)。在只有一個產(chǎn)品族的情況下,抽象工廠模式實際上退化到工廠方法模式。總結(jié)簡單工廠模式是由一個具體的類去創(chuàng)建其他類的實例,父類是相同的,父類是具體的。工廠方法模式是有一個抽象的父類定義公共接口,子類負責(zé)生成具體的對象,這樣做的目的是將類的實例化操作延遲到子類中完成。抽象工廠模式提供一個創(chuàng)建一系列相關(guān)或相互依賴對象的接口,而無須指定他們具體的類。它針對的是有多個產(chǎn)品的等級結(jié)構(gòu)。而工廠方法模式針對的是一個產(chǎn)品的等級結(jié)構(gòu)。Num3:建造(Builder)模式基本概念:是一種對象構(gòu)建的設(shè)計模式,它可以將復(fù)雜對象的建造過程抽象出來(抽象類別),使這個抽象過程的不同實現(xiàn)方法可以構(gòu)造出不同表現(xiàn)(屬性)的對象。Builder模式是一步一步創(chuàng)建一個復(fù)雜的對象,它允許用戶可以只通過指定復(fù)雜對象的類型和內(nèi)容就可以構(gòu)建它們。用戶不知道內(nèi)部的具體構(gòu)建細節(jié)。Builder模式是非常類似抽象工廠模式,細微的區(qū)別大概只有在反復(fù)使用中才能體會到。

?Builder:為創(chuàng)建一個Product對象的各個部件指定抽象接口。ConcreteBuilder:實現(xiàn)Builder的接口以構(gòu)造和裝配該產(chǎn)品的各個部件,定義并明確它所創(chuàng)建的表示,提供一個檢索產(chǎn)品的接口Director:構(gòu)造一個使用Builder接口的對象。Product:表示被構(gòu)造的復(fù)雜對象。ConcreateBuilder創(chuàng)建該產(chǎn)品的內(nèi)部表示并定義它的裝配過程。為何使用是為了將構(gòu)建復(fù)雜對象的過程和它的部件解耦。注意:是解耦過程和部件。因為一個復(fù)雜的對象,不但有很多大量組成部分,如汽車,有很多部件:車輪、方向盤、發(fā)動機,還有各種小零件等等,部件很多,但遠不止這些,如何將這些部件裝配成一輛汽車,這個裝配過程也很復(fù)雜(需要很好的組裝技術(shù)),Builder模式就是為了將部件和組裝過程分開。如何使用首先假設(shè)一個復(fù)雜對象是由多個部件組成的,Builder模式是把復(fù)雜對象的創(chuàng)建和部件的創(chuàng)建分別開來,分別用Builder類和Director類來表示。首先,需要一個接口,它定義如何創(chuàng)建復(fù)雜對象的各個部件:publicinterfaceBuilder{//創(chuàng)建部件A 比如創(chuàng)建汽車車輪voidbuildPartA();

//創(chuàng)建部件B比如創(chuàng)建汽車方向盤voidbuildPartB();//創(chuàng)建部件C比如創(chuàng)建汽車發(fā)動機voidbuildPartC();//返回最后組裝成品結(jié)果(返回最后裝配好的汽車)//成品的組裝過程不在這里進行,而是轉(zhuǎn)移到下面的Director類中進行.//從而實現(xiàn)了解耦過程和部件ProductgetResult();}用Director構(gòu)建最后的復(fù)雜對象,而在上面Builder接口中封裝的是如何創(chuàng)建一個個部件(復(fù)雜對象是由這些部件組成的),也就是說Director的內(nèi)容是如何將部件最后組裝成成品:publicclassDirector{privateBuilderbuilder;publicDirector(Builderbuilder){this.builder=builder;}//將部件partApartBpartC最后組成復(fù)雜對象//這里是將車輪方向盤和發(fā)動機組裝成汽車的過程publicvoidconstruet(){builder.buildPartA();builder.buildPartB();builder.buildPartC();}}Builder的具體實現(xiàn)ConcreteBuilder:?通過具體完成接口Builder來構(gòu)建或裝配產(chǎn)品的部件;定義并明確它所要創(chuàng)建的是什么具體東西;

提供一個可以重新獲取產(chǎn)品的接口。publicclassConcreteBuilderimplementsBuilder{PartpartA,partB,partC;publicvoidbuildPartA(){//這里是具體如何構(gòu)建}publicvoidbuildPartB(){//這里是具體如何構(gòu)建}publicvoidbuildPartC(){//這里是具體如何構(gòu)建}publicProductgetResult(){//返回最后組裝成品結(jié)果}}復(fù)雜對象:產(chǎn)品Product:publicinterfaceProduct{}復(fù)雜對象的部件:publicinterfacePart{}我們看看如何調(diào)用Builder模式:ConcreteBuilderbuilder=newConcreteBuilder();Directordirector=newDirector(builder);director.construet();Productproduct二builder.getResult();

Builder模式的應(yīng)用在Java實際使用中,我們經(jīng)常用到"池"(Pool)的概念,當(dāng)資源提供者無法提供足夠的資源,并且這些資源需要被很多用戶反復(fù)共享時,就需要使用池。"池"實際是一段內(nèi)存,當(dāng)池中有一些復(fù)雜的資源的"斷肢"(比如數(shù)據(jù)庫的連接池,也許有時一個連接會中斷),如果循環(huán)再利用這些"斷肢",將提高內(nèi)存使用效率,提高池的性能。修改Builder模式中Director類使之能診斷"斷肢"斷在哪個部件上,再修復(fù)這個部件。Num4:觀察者模式基本概念:觀察者模式定義了一種一對多的依賴關(guān)系,讓多個觀察者對象同時監(jiān)聽某一主題對象。這個主題對象在狀態(tài)發(fā)生變化時,會通知所有觀察者對象,使它們能夠自動更新自己。觀察者模式又叫發(fā)布-訂閱(Publish/Subscribe)模式。UML結(jié)構(gòu)圖上圖是Observer模式的結(jié)構(gòu)圖,讓我們可以進行更方便的描述:Subject類:它把所有對觀察者對象的引用保存在一個聚集里,每個主題都可以有任何數(shù)量的觀察著。抽象主題提供一個接口,可以增加和刪除觀察著對象。Observer類:抽象觀察者,為所有的具體觀察者定義一個接口,在得到主題的通知時更新自己。

?ConcreteSubject類:具體主題,將有關(guān)狀態(tài)存入具體觀察者對象;在具體主題的內(nèi)部狀態(tài)改變時,給所有登記過的觀察者發(fā)出通知。?ConcreteObserver類:具體觀察者,實現(xiàn)抽象觀察者角色所要求的更新接口,以便使本身的狀態(tài)與主題的狀態(tài)相協(xié)調(diào)。如何使用例如:老師有電話號碼,學(xué)生需要知道老師的電話號碼以便于在合適的時候撥打,在這樣的組合中,老師就是一個被觀察者(Subject),學(xué)生就是需要知道信息的觀察者,當(dāng)老師的電話號碼發(fā)生改變時,學(xué)生得到通知,并更新相應(yīng)的電話記錄。先創(chuàng)建一個Subject類:/**Subject(目標,Subject):*目標知道它的觀察者??梢杂腥我舛鄠€觀察者觀察同一個目標。*提供注冊和刪除觀察者對象的接口。*/publicinterfaceSubject{publicvoidattach(ObservermObserver);publicvoiddetach(ObservermObserver);publicvoidnotice();}創(chuàng)建Observer類:/**Observer(觀察者,Observer):*為那些在目標發(fā)生改變時需要獲得通知的對象定義一個更新接口。*/publicinterfaceObserver{publicvoidupdate();}創(chuàng)建ConcreteSubject類:/**ConcreteSubject(具體目標,Teacher)*將有關(guān)狀態(tài)存入各ConcreteObserve對象。

*當(dāng)他的狀態(tài)發(fā)生改變時,向他的各個觀察者發(fā)出通知。*/publicclassTeacherimplementsSubject{privateStringphone;privateVectorstudents;publicTeacher(){phone= ;students=newVector();}@Overridepublicvoidattach(ObservermObserver){students.add(mObserver);}@Overridepublicvoiddetach(ObservermObserver){students.remove(mObserver);}@Overridepublicvoidnotice(){for(inti=0;i<students.size();i++){((Observer)students.get(i)).update();

publicStringgetPhone(){returnphone;}publicvoidsetPhone(Stringphone){this.phone=phone;notice();}}創(chuàng)建ConcreteObserver類:/***ConcreteObserver(具體觀察者,Student):*維護一個指向ConcreteSubject對象的引用。*存儲有關(guān)狀態(tài),這些狀態(tài)應(yīng)與目標的狀態(tài)保持一致。*實現(xiàn)Observer的更新接口以使自身狀態(tài)與目標的狀態(tài)保持一致。*/publicclassStudentimplementsObserver{privateStringname;privateStringphone;privateTeachermTeacher;publicStudent(Stringname,Teachert){t=name;mTeacher=t;}publicvoidshow(){

System.out.println("Name:"+name+"\nTeacher'sphone:"+phone);@0verridepublicvoidupdate(){phone=mTeacher.getPhone();}}客戶端測試:/***觀察者(Observer)模式測試類*/publicclassObserverClient{publicstaticvoidmain(String[]args){Vectorstudents=newVector();Teachert二newTeacher();for(inti二0;i<10;i++){Studentst二newStudent("Andy.Chen"+i,t);students.add(st);t.attach(st);}System.out.println("WelcometoAndy.ChenBlog!"+"\n"+"ObserverPatterns."+"\n"t.setPhone("12345678");

for(inti=0;i<3;i++)((Student)students.get(i)).show()t.setPhone("87654321");for(inti=0;i<3;i++)((Student)students.get(i)).show();}}程序運行結(jié)果如下:WelcometoAndy.ChenBlog!ObserverPatterns.Name:Andy.ChenOTeacher'sphone:12345678Name:Andy.Chen1Teacher'sphone:12345678Name:Andy.Chen2Teacher'sphone:12345678Name:Andy.ChenOTeacher'sphone:87654321Name:Andy.Chen1Teacher'sphone:87654321Name:Andy.Chen2Teacher'sphone:87654321總結(jié)觀察者模式何時適用?當(dāng)一個抽象模型有兩個方面,其中一個方面依賴于另一方面。將這二者封裝在獨立的對象中可以使他們各自獨立地改變和復(fù)用。

?當(dāng)對一個對象的改變需要同時改變其它對象,而不知道具體由多少對象有待改變。?當(dāng)一個對象必須通知其他對象,而它又不能假定其他對象是誰,換言之,你不希望這些對象是緊密耦合的。讓耦合的雙方都依賴于抽象,而不是依賴于具體。Num5:適配器(Adapter)模式基本概念:適配器模式把一個類的接口變換成客戶端所期待的另一種接口,從而使原本因接口不匹配而無法在一起工作的兩個類能夠在一起工作。適配器模式的用途用電器做例子,筆記本電腦的插頭一般都是三相的,即除了陽極、陰極外,還有一個地極。而有些地方的電源插座卻只有兩極,沒有地極。電源插座與筆記本電腦的電源插頭不匹配使得筆記本電腦無法使用。這時候一個三相到兩相的轉(zhuǎn)換器(適配器)就能解決此問題,而這正像是本模式所做的事情。適配器模式的結(jié)構(gòu)適配器模式有類的適配器模式和對象的適配器模式兩種不同的形式。類適配器模式:在上圖中可以看出,Adaptee類并沒有sampleOperation2()方法,而客戶端則期待這個方法。為使客戶端能夠使用Adaptee類,提供一個中間環(huán)節(jié),即類Adapter,把Adaptee的API與Target類的API銜接起來。Adapter與Adaptee是繼承關(guān)系,這決定了這個適配器模式是類的:?目標(Target)角色:這就是所期待得到的接口。注意:由于這里討論的是類適配器模式,因此目標不可以是類。源(Adapee)角色:現(xiàn)在需要適配的接口。適配器(Adaper)角色:適配器類是本模式的核心。適配器把源接口轉(zhuǎn)換成目標接口。顯然,這一角色不可以是接口,而必須是具體類。

示例代碼:publicinterfaceTarget{/***這是源類Adaptee也有的方法*/publicvoidsampleOperationl();/***這是源類Adapteee沒有的方法*/publicvoidsampleOperation2();}上面給出的是目標角色的源代碼,這個角色是以一個Java接口的形式實現(xiàn)的。可以看出,這個接口聲明了兩個方法:sampleOperation1()和sampleOperation2()。而源角色Adaptee是一個具體類,它有一個sampleOperation1()方法,但是沒有sampleOperation2()方法。publicclassAdaptee{publicvoidsampleOperation1(){}}適配器角色Adapter擴展了Adaptee,同時又實現(xiàn)了目標(Target)接口。由于Adaptee沒有提供sampleOperation2()方法,而目標接口又要求這個方法,因此適配器角色Adapter實現(xiàn)了這個方法。publicclassAdapterextendsAdapteeimplementsTarget{/***由于源類Adaptee沒有方法sampleOperation2()*因此適配器補充上這個方法*/@OverridepublicvoidsampleOperation2(){//寫相關(guān)的代碼

}對象適配器模式:從上圖可以看出,Adaptee類并沒有sampleOperation2()方法,而客戶端則期待這個方法。為使客戶端能夠使用Adaptee類,需要提供一個包裝(Wrapper)類Adapter。這個包裝類包裝了一個Adaptee的實例,從而此包裝類能夠把Adaptee的API與Target類的API銜接起來。Adapter與Adaptee是委派關(guān)系,這決定了適配器模式是對象的。示例代碼:publicinterfaceTarget{/***這是源類Adaptee也有的方法*/publicvoidsampleOperationl();/***這是源類Adapteee沒有的方法*/publicvoidsampleOperation2();

publicclassAdaptee{publicvoidsampleOperation1(){}}適配器類:publicclassAdapter{privateAdapteeadaptee;publicAdapter(Adapteeadaptee){this.adaptee=adaptee;}/**源類Adaptee有方法sampleOperationl*因此適配器類直接委派即可*/publicvoidsampleOperation1(){this.adaptee.sampleOperationl();}/**源類Adaptee沒有方法sampleOperation2*因此由適配器類需要補充此方法*/publicvoidsampleOperation2(){//寫相關(guān)的代碼}}類適配器和對象適配器的權(quán)衡類適配器使用對象繼承的方式,是靜態(tài)的定義方式;而對象適配器使用對象組合的方式,是動態(tài)組合的方式。

?對于類適配器由于適配器直接繼承了Adaptee,使得適配器不能和Adaptee的子類一起工作,因為繼承是靜態(tài)的關(guān)系,當(dāng)適配器繼承了Adaptee后,就不可能再去處理Adaptee的子類了。?對于對象適配器一個適配器可以把多種不同的源適配到同一個目標。換言之,同一個適配器可以把源類和它的子類都適配到目標接口。因為對象適配器采用的是對象組合的關(guān)系,只要對象類型正確,是不是子類都無所謂。?對于類適配器適配器可以重定義Adaptee的部分行為,相當(dāng)于子類覆蓋父類的部分實現(xiàn)方法。?對于對象適配器要重定義Adaptee的行為比較困難,這種情況下,需要定義Adaptee的子類來實現(xiàn)重定義,然后讓適配器組合子類。雖然重定義Adaptee的行為比較困難,但是想要增加一些新的行為則方便的很,而且新增加的行為可同時適用于所有的源。?對于類適配器,僅僅引入了一個對象,并不需要額外的引用來間接得到Adapteeo?對于對象適配器,需要額外的引用來間接得到Adapteeo建議盡量使用對象適配器的實現(xiàn)方式,多用合成或聚合、少用繼承。當(dāng)然,具體問題具體分析,根據(jù)需要來選用實現(xiàn)方式,最適合的才是最好的。適配器模式的優(yōu)點?更好的復(fù)用性:系統(tǒng)需要使用現(xiàn)有的類,而此類的接口不符合系統(tǒng)的需要。那么通過適配器模式就可以讓這些功能得到更好的復(fù)用。?更好的擴展性:在實現(xiàn)適配器功能的時候,可以調(diào)用自己開發(fā)的功能,從而自然地擴展系統(tǒng)的功能。適配器模式的缺點過多的使用適配器,會讓系統(tǒng)非常零亂,不易整體進行把握。比如,明明看到調(diào)用的是A接口,其實內(nèi)部被適配成了B接口的實現(xiàn),一個系統(tǒng)如果太多出現(xiàn)這種情況,無異于一場災(zāi)難。因此如果不是很有必要,可以不使用適配器,而是直接對系統(tǒng)進行重構(gòu)。Num6:代理模式基本概念:為其他對象提供一種代理以控制對這個對象的訪問。也可以說,在出發(fā)點到目的地之間有一道中間層,意為代理。為什么要使用?授權(quán)機制不同級別的用戶對同一對象擁有不同的訪問權(quán)利,如在論壇系統(tǒng)中,就使用proxy進行授權(quán)機制控制,訪問論壇有兩種人:注冊用戶和游客(未注冊用戶),論壇就通過類似ForumProxy這樣的代理來控制這兩種用戶對論壇的訪問權(quán)限。?某個客戶端不能直接操作到某個對象,但又必須和那個對象有所互動。舉例兩個具體情況:?如果那個對象是一個是很大的圖片,需要花費很長時間才能顯示出來,那么當(dāng)這個圖片包含在文檔中時,使用編輯器或瀏覽器打開這個文檔,打開文檔必須很迅速,不能等待大圖片處理完成,這時需要做個圖片Proxy來代替真正的圖片。

如果那個對象在Internet的某個遠端服務(wù)器上,直接操作這個對象因為網(wǎng)絡(luò)速度原因可能比較慢,那我們可以先用Proxy來代替那個對象??傊瓌t是,對于開銷很大的對象,只有在使用它時才創(chuàng)建,這個原則可以為我們節(jié)省很多寶貴的Java內(nèi)存。所以,有些人認為Java耗費資源內(nèi)存,我以為這和程序編制思路也有一定的關(guān)系。如何使用以論壇系統(tǒng)為例,訪問論壇系統(tǒng)的用戶有多種類型:注冊普通用戶、論壇管理者、系統(tǒng)管理者、游客。注冊普通用戶才能發(fā)言,論壇管理者可以管理他被授權(quán)的論壇,系統(tǒng)管理者可以管理所有事務(wù)等,這些權(quán)限劃分和管理是使用Proxy完成的。在Forum中陳列了有關(guān)論壇操作的主要行為,如論壇名稱,論壇描述的獲取和修改,帖子發(fā)表刪除編輯等,在ForumPermissions中定義了各種級別權(quán)限的用戶:publicclassForumPermissionsimplementsCacheable{/**Permissiontoreadobject.*/publicstaticfinalintREAD=0;/**Permissiontoadministertheentiresytem.*/publicstaticfinalintSYSTEM_ADMIN=1;/**Permissiontoadministeraparticularforum.*/publicstaticfinalintFORUM_ADMIN=2;/**Permissiontoadministeraparticularuser.*/publicstaticfinalintUSER_ADMIN=3;/***Permissiontoadministeraparticulargroup.

*/publicstaticfinalintGROUP_ADMIN=4;/**Permissiontomoderatethreads.*/publicstaticfinalintMODERATE_THREADS=5;/**Permissiontocreateanewthread.*/publicstaticfinalintCREATE_THREAD=6;/**Permissiontocreateanewmessage.*/publicstaticfinalintCREATE_MESSAGE=7;/**Permissiontomoderatemessages.*/publicstaticfinalintMODERATE_MESSAGES=8;publicbooleanisSystemOrForumAdmin(){return(values[FORUM_ADMIN]||values[SYSTEM_ADMIN]);}//相關(guān)操作代碼}因此,F(xiàn)orum中各種操作權(quán)限是和ForumPermissions定義的用戶級別有關(guān)系的,作為接口Forum的實現(xiàn):ForumProxy正是將這種對應(yīng)關(guān)系聯(lián)系起來。比如,修改Forum的名稱,只有論壇管理者或系統(tǒng)管理者可以修改,代碼如下:privateForumPermissionspermissions;privateForumforum;this.authorization二authorization;publicForumProxy(Forumforum,Authorizationauthorization,ForumPermissionspermissions){this.forum=forum;this.authorization二authorization;this.permissions=permissions;}publicvoidsetName(Stringname)throwsUnauthorizedException,ForumAlreadyExistsException{//只有是系統(tǒng)或論壇管理者才可以修改名稱if(permissions.isSystemOrForumAdmin()){forum.setName(name);}else{thrownewUnauthorizedException();}}}而DbForum才是接口Forum的真正實現(xiàn),以修改論壇名稱為例:

publicvoidsetName(Stringname)throwsForumAlreadyExistsExceptiont=name;//這里真正將新名稱保存到數(shù)據(jù)庫中saveToDb();}凡是涉及到對論壇名稱修改這一事件,其他程序都首先得和ForumProxy打交道,由ForumProxy決定是否有權(quán)限做某一樣事情,F(xiàn)orumProxy是個名副其實的"網(wǎng)關(guān)","安全代理系統(tǒng)"。在平時應(yīng)用中,無可避免總要涉及到系統(tǒng)的授權(quán)或安全體系,不管你有無意識的使用Proxy,實際你已經(jīng)在使用Proxy了。流程圖Num7:裝飾模式基本概念:裝飾模式(Decorator),動態(tài)地給一個對象添加一些額外的職責(zé),就增加功能來說,裝飾模式比生成子類更為靈活。UML結(jié)構(gòu)圖

Component是定義一個對象接口,可以給這些對象動態(tài)地添加職責(zé)。ConcreteComponent是定義了一個具體的對象,也可以給這個對象添加一些職責(zé)。Decorator是裝飾抽象類,繼承了Component,從外類來擴展Component類的功能,但對于Comp

溫馨提示

  • 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論