版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第Java設(shè)計(jì)模式之裝飾器模式本文由老王將建好的書房計(jì)劃請(qǐng)小王來(lái)幫忙,小王卻想謀權(quán)篡位,老王通過(guò)教育他引出裝飾器設(shè)計(jì)模式,第二部分針對(duì)老王提出的建設(shè)性意見實(shí)現(xiàn)裝飾器模式,第三部分針對(duì)裝飾器模式在Jdk中的IO、Spring中的緩存管理器、Mybatis的運(yùn)用來(lái)加強(qiáng)我們的理解,第四部分說(shuō)明裝飾器模式和代理模式的區(qū)別及他們各自的應(yīng)用場(chǎng)景。
讀者可以拉取完整代碼到本地進(jìn)行學(xué)習(xí),實(shí)現(xiàn)代碼均測(cè)試通過(guò)后上傳到碼云,本地源碼下載。
一、引出問題
上篇文章(Java設(shè)計(jì)模式之組合模式)對(duì)老王的書架改造以后,老王是相當(dāng)?shù)臐M意,看小王能力突出,這不老王又有了新的需求。
經(jīng)過(guò)組合模式以后老王的書被管理的井井有條,但是隨著書的增多,老王就有一些忙不過(guò)來(lái)了,老王就想讓小王幫他處理一些額外的事,比如在買書之前打掃一下書房,在晚上的時(shí)候把書房的門鎖一下;或者有人借書之前做一下記錄,借書者還書以后小王接收一下,等等。
小王聽完說(shuō)這有何難,說(shuō)完擼起袖子就準(zhǔn)備改老王的代碼。老王急忙攔住了他,你真是個(gè)呆瓜,我寫的代碼你憑什么要?jiǎng)?,你改了?huì)不會(huì)影響我的業(yè)務(wù)邏輯,平時(shí)讓你多看書你不聽,之前學(xué)的設(shè)計(jì)模式呢?不拿出來(lái)用,眼看著讓他吃灰。
小王不好意思的撓撓頭,翻出來(lái)了他的設(shè)計(jì)模式寶典,開始尋找合適的設(shè)計(jì)模式。
小王大喊有了,之前說(shuō)過(guò)的代理模式可以很好的解決這個(gè)問題,代理模式可以動(dòng)態(tài)的增強(qiáng)對(duì)象的一些特性,我準(zhǔn)備使用代理模式完成這個(gè)需求。
老王聽完止不住的搖搖頭,看來(lái)你是打算謀權(quán)篡位了,你是想要我整個(gè)書房的權(quán)利呀!
老王解釋說(shuō),代理模式是可以實(shí)現(xiàn)這個(gè)需求,但是在這個(gè)場(chǎng)景下顯然代理模式不合適,代理模式是著重對(duì)對(duì)象的控制,而我們今天的需求是在該對(duì)象的基礎(chǔ)之上增加他的一些功能,我們各自的業(yè)務(wù)獨(dú)立發(fā)展互不干擾。
二、裝飾器模式概念與使用
實(shí)際上,在原對(duì)象的基礎(chǔ)之上增加其功能就是屬于裝飾器模式。
裝飾器模式(DecoratorPattern)允許向一個(gè)現(xiàn)有的對(duì)象添加新的功能,同時(shí)又不改變其結(jié)構(gòu)。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它是作為現(xiàn)有的類的一個(gè)包裝。
在裝飾器模式中應(yīng)該是有四個(gè)角色:
①Component抽象構(gòu)件(老王抽象方法)
②ConcreteComponent具體構(gòu)件(老王實(shí)現(xiàn)方法)
③Decorator裝飾角色(裝飾者小王)
④ConcreteDecorator具體裝飾角色(裝飾者小王實(shí)現(xiàn)方法)
在裝飾器模式中,需要增強(qiáng)的類(被裝飾者)要實(shí)現(xiàn)接口,裝飾者繼承被裝飾者的接口,并將被裝飾者的實(shí)例傳進(jìn)去,在具體裝飾角色中調(diào)用被裝飾者的方法,在其前后定義增強(qiáng)的方法,在實(shí)際應(yīng)用中往往裝飾角色和具體裝飾角色合二為一。
我們看下具體的代碼實(shí)現(xiàn):
抽象構(gòu)件:
/**
*書的抽象構(gòu)件
*@authortcy
*@Date10-08-2025
publicabstractclassComponentBook{
*借書
publicabstractvoidborrowBook();
*買書
publicabstractvoidbuyBook();
}
書的具體構(gòu)件:
/**
*書的具體構(gòu)件
*@authortcy
*@Date10-08-2025
publicclassConcreteComponentBookextendsComponentBook{
@Override
publicvoidborrowBook(){
System.out.println("老王的書借出去...");
@Override
publicvoidbuyBook(){
System.out.println("老王的書買回來(lái)...");
}
裝飾角色:
/**
*書的裝飾者
*@authortcy
*@Date10-08-2025
publicclassDecoratorBookextendsComponentBook{
privateComponentBookcomponentBook;
DecoratorBook(ComponentBookcomponentBook){
ponentBook=componentBook;
@Override
publicvoidborrowBook(){
ponentBook.borrowBook();
@Override
publicvoidbuyBook(){
ponentBook.buyBook();
}
書的具體裝飾角色:
/**
*子類里寫了并且使用了無(wú)參的構(gòu)造方法但是它的父類(祖先)中卻至少有一個(gè)是沒有無(wú)參構(gòu)造方法的
*@authortcy
*@Date10-08-2025
publicclassConcreteDecoratorBook1extendsDecoratorBook{
ConcreteDecoratorBook1(ComponentBookcomponentBook){
super(componentBook);
publicvoidcleanRoom(){
System.out.println("打掃書房...");
publicvoidshutRoom(){
System.out.println("關(guān)閉書房...");
publicvoidrecordBook(){
System.out.println("記錄借出記錄...");
publicvoidreturnBook(){
System.out.println("收到借出去的書...");
@Override
publicvoidbuyBook(){
this.cleanRoom();
super.buyBook();
this.shutRoom();
System.out.println("----------------------------");
@Override
publicvoidborrowBook(){
this.recordBook();
super.borrowBook();
this.returnBook();
System.out.println("----------------------------");
}
如果讀者的Java基礎(chǔ)扎實(shí),理解裝飾器還是比較輕松的,裝飾器的實(shí)現(xiàn)方式很直觀,需要特別指出的是,在書的具體裝飾角色中,要顯示的定義一個(gè)構(gòu)造方法。
基礎(chǔ)不太扎實(shí)的讀者可能會(huì)有一個(gè)疑問,在Java的類中默認(rèn)不是會(huì)有一個(gè)無(wú)參的構(gòu)造方法嗎?為什么這里還需要定義呢
在java中一個(gè)類只要有父類,那么在它實(shí)例化的時(shí)候,一定是從頂級(jí)的父類開始創(chuàng)建。
也就是說(shuō)當(dāng)你用子類的無(wú)參構(gòu)造函數(shù)創(chuàng)建子類對(duì)象時(shí),會(huì)去先遞歸調(diào)用父類的無(wú)參構(gòu)造方法,這時(shí)候如果某個(gè)類的父類沒有無(wú)參構(gòu)造方法就會(huì)編譯出差。所以我們?cè)谧宇愔锌梢允謩?dòng)定義一個(gè)無(wú)參方法,或者在父類中顯示的定義一個(gè)構(gòu)造方法。
客戶端:
/**
*@authortcy
*@Date09-08-2025
publicclass{
publicstaticvoidmain(String[]args){
ComponentBookcomponentBook=newConcreteComponentBook();
componentBook=newConcreteDecoratorBook1(componentBook);
componentBook.borrowBook();
componentBook.buyBook();
}
方法調(diào)用后我們可以看到執(zhí)行結(jié)果:
記錄借出記錄...
老王的書借出去...
收到借出去的書...
----------------------------
打掃書房...
老王的書買回來(lái)...
關(guān)閉書房...
----------------------------
在老王借書和買書的這個(gè)事件中,成功的織入進(jìn)去小王的方法,這樣也就實(shí)現(xiàn)了裝飾器模式。
為了加強(qiáng)理解我們接著看裝飾器模式在我們經(jīng)常接觸的源碼中的運(yùn)用。
1、jdk中的應(yīng)用IO
裝飾器在java中最典型的應(yīng)用就是IO,我們知道在IO家族中有各種各樣的流,而流往往都是作用在子類之上,然后增加其附加功能,我們以InputStream舉例。
InputStream是字節(jié)輸入流,此抽象類是表示字節(jié)輸入流的所有類的超類。
FileInputStream是InputStream的一個(gè)實(shí)現(xiàn)父類,BufferedInputStream是FileInputStream的實(shí)現(xiàn)父類。
實(shí)際BufferedInputStream就是裝飾者,InputStream就是抽象構(gòu)件,F(xiàn)ileInputStream是具體構(gòu)件,BufferedInputStream就是對(duì)FileInputStream進(jìn)行了包裝。
我們看具體的應(yīng)用:
FileInputStreamfileInputStream=newFileInputStream(filePath);
BufferedInputStreambufferedInputStream=newBufferedInputStream(fileInputStream);
直接將FileInputStream的實(shí)例傳給BufferedInputStream的構(gòu)造方法,就能調(diào)用BufferedInputStream增強(qiáng)的一些方法了。
我們具體看BufferedInputStream裝飾器類:
publicclassBufferedInputStreamextendsFilterInputStream{
privatestaticintDEFAULT_BUFFER_SIZE=8192;
protectedintmarklimit;
publicBufferedInputStream(InputStreamin){
this(in,DEFAULT_BUFFER_SIZE);
//增強(qiáng)的方法
privatevoidfill()throwsIOException{
byte[]buffer=getBufIfOpen();
if(markpos0)
pos=0;/*nomark:throwawaythebuffer*/
elseif(pos=buffer.length)/*noroomleftinbuffer*/
if(markpos0){/*canthrowawayearlypartofthebuffer*/
intsz=pos-markpos;
System.arraycopy(buffer,markpos,buffer,0,sz);
pos=sz;
markpos=0;
}elseif(buffer.length=marklimit){
markpos=-1;/*buffergottoobig,invalidatemark*/
pos=0;/*dropbuffercontents*/
}elseif(buffer.length=MAX_BUFFER_SIZE){
thrownewOutOfMemoryError("Requiredarraysizetoolarge");
}else{/*growbuffer*/
intnsz=(pos=MAX_BUFFER_SIZE-pos)
pos*2:MAX_BUFFER_SIZE;
if(nszmarklimit)
nsz=marklimit;
bytenbuf[]=newbyte[nsz];
System.arraycopy(buffer,0,nbuf,0,pos);
if(!bufUpareAndSet(this,buffer,nbuf)){
//Can'treplacebufiftherewasanasyncclose.
//Note:Thiswouldneedtobechangediffill()
//isevermadeaccessibletomultiplethreads.
//Butfornow,theonlywayCAScanfailisviaclose.
//assertbuf==null;
thrownewIOException("Streamclosed");
buffer=nbuf;
count=pos;
intn=getInIfOpen().read(buffer,pos,buffer.length-pos);
if(n0)
count=n+pos;
...
BufferedInputStream類中有許多其他的方法,就是對(duì)FileInputStream類的增強(qiáng)。
2、Spring中的運(yùn)用
Spring使用裝飾器模式有兩個(gè)典型的特征,一個(gè)是類名中含有Wrapper,另一類是含有Decorator,功能也即動(dòng)態(tài)的給某些類增加一些額外的功能。
TransactionAwareCacheDecorator是處理spring有事務(wù)的時(shí)候緩存的類,我們?cè)谑褂胹pring的cache注解實(shí)現(xiàn)緩存的時(shí)候,當(dāng)出現(xiàn)事務(wù)的時(shí)候,那么緩存的同步性就需要做相應(yīng)的處理了,于是就有了這個(gè)裝飾者。
publicclassTransactionAwareCacheDecoratorimplementsCache{
//抽象構(gòu)件
privatefinalCachetargetCache;
*CreateanewTransactionAwareCacheforthegiventargetCache.
*@paramtargetCachethetargetCachetodecorate
publicTransactionAwareCacheDecorator(CachetargetCache){
Assert.notNull(targetCache,"TargetCachemustnotbenull");
this.targetCache=targetCache;
/**直接調(diào)用未增強(qiáng)
*ReturnthetargetCachethatthisCacheshoulddelegateto.
publicCachegetTargetCache(){
returnthis.targetCache;
//直接調(diào)用未增強(qiáng)
@Override
publicStringgetName(){
returnthis.targetCache.getName();
//直接調(diào)用未增強(qiáng)
@Override
publicObjectgetNativeCache(){
returnthis.targetCache.getNativeCache();
//直接調(diào)用未增強(qiáng)
@Override
@Nullable
publicValueWrapperget(Objectkey){
returnthis.targetCache.get(key);
//直接調(diào)用未增強(qiáng)
@Override
publicTTget(Objectkey,@NullableClassTtype){
returnthis.targetCache.get(key,type);
//直接調(diào)用未增強(qiáng)
@Override
@Nullable
publicTTget(Objectkey,CallableTvalueLoader){
returnthis.targetCache.get(key,valueLoader);
//先進(jìn)行判斷確定是否需要增強(qiáng)
@Override
publicvoidput(finalObjectkey,@NullablefinalObjectvalue){
if(TransactionSynchronizationManager.isSynchronizationActive()){
TransactionSynchronizationManager.registerSynchronization(newTransactionSynchronizationAdapter(){
@Override
publicvoidafterCommit(){
TransactionAwareCacheDecorator.this.targetCache.put(key,value);
else{
this.targetCache.put(key,value);
}
Cache是抽象構(gòu)件,TransactionAwareCacheDecorator就是裝飾者,而Cache的實(shí)現(xiàn)類就是具體構(gòu)件。
因?yàn)椴⒎撬械姆椒ǘ紩?huì)使用事務(wù),有的普通方法就不需要裝飾,有的就需要,所以就使用了裝飾者模式來(lái)完成。
比如put()方法:
@Override
publicvoidput(finalObjectkey,@NullablefinalObjectvalue){
if(TransactionSynchronizationManager.isSynchronizationActive()){
TransactionSynchronizationManager.registerSynchronization(newTransactionSynchronizationAdapter(){
@Override
publicvoidafterCommit(){
TransactionAwareCacheDecorator.this.targetCache.put(key,value);
else{
this.targetCache.put(key,value);
}
會(huì)在put前判斷是否開啟了事務(wù)TransactionSynchronizationManager.isSynchronizationActive(),如果開啟事務(wù)就調(diào)用一下額外的方法,如果沒有開始事務(wù)就調(diào)用默認(rèn)的方法。
我們舉的這個(gè)例子調(diào)用的就是TransactionSynchronizationManager.registerSynchronization()方法,也即是為當(dāng)前線程注冊(cè)一個(gè)新的事務(wù)同步。
在Spring中將裝飾角色和具體裝飾角色合二為一,直接在裝飾者中實(shí)現(xiàn)要增加的方法。
3、MyBatista的運(yùn)用
了解過(guò)MyBatis的大致執(zhí)行流程的讀者應(yīng)該知道,Executor是MyBatis執(zhí)行器,是MyBatis調(diào)度的核心,負(fù)責(zé)SQL語(yǔ)句的生成和查詢緩存的維護(hù);CachingExecutor是一個(gè)Executor的裝飾器,給一個(gè)Executor增加了緩存的功能。此時(shí)可以看做是對(duì)Executor類的一個(gè)增強(qiáng),故使用裝飾器模式是合適的。
我們首先看下Executor類的繼承結(jié)構(gòu)。
我們將關(guān)鍵的CachingExecutor代碼放上:
publicclassCachingExecutorimplementsExecutor{
//持有組件對(duì)象
privateExecutordelegate;
privateTransactionalCacheMan
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 牧醫(yī)實(shí)訓(xùn)室使用管理制度(3篇)
- 背包廠員工管理制度范本(3篇)
- 造價(jià)公司的安全管理制度(3篇)
- 鐵路管理制度標(biāo)語(yǔ)圖片(3篇)
- 《GA 663-2006互聯(lián)網(wǎng)公共上網(wǎng)服務(wù)場(chǎng)所信息安全管理系統(tǒng)遠(yuǎn)程通訊端接口技術(shù)要求》專題研究報(bào)告深度
- 養(yǎng)老院志愿服務(wù)制度
- 養(yǎng)老院入住老人精神慰藉與關(guān)愛制度
- 養(yǎng)老院服務(wù)質(zhì)量投訴處理制度
- 企業(yè)員工培訓(xùn)與技能提升計(jì)劃制度
- 企業(yè)內(nèi)部保密責(zé)任追究制度
- 2023年版測(cè)量結(jié)果的計(jì)量溯源性要求
- 建筑能耗與碳排放研究報(bào)告
- GB 29415-2013耐火電纜槽盒
- 中國(guó)古代經(jīng)濟(jì)試題
- 真空采血管的分類及應(yīng)用及采血順序課件
- 軟件定義汽車:產(chǎn)業(yè)生態(tài)創(chuàng)新白皮書
- 安裝工程實(shí)體質(zhì)量情況評(píng)價(jià)表
- 動(dòng)力觸探試驗(yàn)課件
- 城市軌道交通安全管理課件(完整版)
- 八大浪費(fèi)培訓(xùn)(整理)
- 幼兒園機(jī)器人課件.ppt
評(píng)論
0/150
提交評(píng)論