Decorate(
裝飾者模式
)
裝飾者模式以對(duì)客戶(hù)端透明的方式動(dòng)態(tài)的為對(duì)象增加責(zé)任。此模式提供了一個(gè)比繼承更為靈活的替代方案來(lái)擴(kuò)展對(duì)象的功能,避免了繼承方法產(chǎn)生的類(lèi)激增問(wèn)題,而且更方便更改對(duì)象的責(zé)任。
我們經(jīng)常要為某一些個(gè)別的對(duì)象增加一些新的職責(zé),并不是全部的類(lèi)。例如我們系統(tǒng)留言反饋板塊中可能需要過(guò)濾用戶(hù)輸入留言中的一些詞匯(例如政治敏感詞匯、色情詞匯等)、還可能對(duì)用戶(hù)輸入留言進(jìn)行一些修飾(例如對(duì)用戶(hù)輸入的
URL
自動(dòng)加上超鏈接、對(duì)用戶(hù)輸入的
UBB
代碼進(jìn)行轉(zhuǎn)換的)、還可能將用戶(hù)輸入的內(nèi)容定時(shí)發(fā)送的網(wǎng)管的郵箱中等等。如果使用類(lèi)繼承的方式進(jìn)行設(shè)計(jì),我們可能要設(shè)計(jì)一個(gè)接口
BodyContentFilterIntf
,然后在由
BodyContentFilterIntf
派生出
SensitiveWordContentFilter
、
HtmlContentFilter
、
SendEmailContentFilter
等類(lèi)。但是如果還要要求同時(shí)能過(guò)濾敏感詞匯并能進(jìn)行修飾、或者過(guò)濾敏感詞匯之后把用戶(hù)輸入的留言發(fā)送到網(wǎng)管郵箱等等,這樣就要增加
SensitiveWordHtmlContentFilter
、
SensitiveWordSendEmaillContentFilter
等類(lèi),這種方式導(dǎo)致了子類(lèi)瀑發(fā)式的產(chǎn)生。
一個(gè)靈活的方法是將過(guò)濾器嵌入另一個(gè)過(guò)濾器中,由這個(gè)過(guò)濾器來(lái)負(fù)責(zé)調(diào)用被嵌入過(guò)濾器的方法并執(zhí)行自己的過(guò)濾器方法。
我們稱(chēng)這個(gè)嵌入的
過(guò)濾器
為裝飾(
Decorator
)。
這個(gè)裝飾與過(guò)濾器接口一致
。
裝飾
將請(qǐng)求向前轉(zhuǎn)到到
另一個(gè)過(guò)濾器,并且可能能轉(zhuǎn)發(fā)前后執(zhí)行一些額外的動(dòng)作(如
修飾
、
發(fā)送郵件
),透明性使你可以遞歸的嵌套多個(gè)裝飾,從面可以添加任意多的功能。
其實(shí)
java
中的過(guò)濾器模式應(yīng)用非常多,典型的就是
IO
的
Stream
操作。在
IO
處理中,
Java
將數(shù)據(jù)抽象為流(
Stream
)。在
IO
庫(kù)中,最基本的是
InputStream
和
OutputStream
兩個(gè)分別處理輸出和輸入的對(duì)象,但是在
InputStream
和
OutputStream
中之提供了最簡(jiǎn)單的流處理方法,只能讀入
/
寫(xiě)出字符,沒(méi)有緩沖處理,無(wú)法處理文件,等等。
LineNumberInputStream
、
BufferInputStream
、
StringBufferInputStream
等提供各種不同服務(wù)的類(lèi)只要組合起來(lái)就可以實(shí)現(xiàn)很多功能,如下:
FilterInputStream myStream=new LineNumberInputStream
( new BufferInputStream( new StringBufferInputStream( myStringBuffer)));
多個(gè)的
Decorator
被層疊在一起,最后得到一個(gè)功能強(qiáng)大的流。既能夠被緩沖,又能夠得到行數(shù),這就是
Decorator
的威力!
我們定義一個(gè)接口
BodyContentFilterIntf 來(lái)定義所有過(guò)濾器要實(shí)現(xiàn)的方法:
public interface BodyContentFilterIntf {
? public String filtContent(String aContent) throws ContentFilterException;
}
這個(gè)接口中只有一個(gè)方法
filtContent,將要過(guò)濾的留言傳給aContent參數(shù),filtContent對(duì)aContent進(jìn)行一些處理(如裝飾URL、UBB等),然后將處理后的字符串做為返回值返回;如果留言沒(méi)有通過(guò)過(guò)濾(如含有敏感詞匯等),只要拋出自定義ContentFilterException異常即可。
下面是一個(gè)可能的一個(gè)過(guò)濾器(保證輸入的字?jǐn)?shù)多于50):
public class LengthContentFilter
??? implements BodyContentFilterIntf {
? private BodyContentFilterIntf bodyContentFilterIntf = null;
? public HtmlContentFilter(BodyContentFilterIntf aFilter)
? {
??? bodyContentFilterIntf = aFilter;
? }
?
? public String filtContent(String aContent) throws ContentFilterException {
?? String l_Content = aContent;
?? If (bodyContentFilterIntf!=null)
??? _Content = bodyContentFilterIntf .filtContent(l_Content);
if (aContent.length()<=50)
? throw new ContentFilterException (
“
輸入的字?jǐn)?shù)不能少于50!
”
);
??? return aContext;
?
? }
}
這是另一個(gè)過(guò)濾器
(
偽碼
,
用來(lái)實(shí)現(xiàn)向網(wǎng)管郵箱發(fā)送郵件
)
public class SendEmailContentFilter
??? implements BodyContentFilterIntf {
?
? private BodyContentFilterIntf bodyContentFilterIntf = null;
? public SendEmailContentFilter(BodyContentFilterIntf aFilter)
? {
??? bodyContentFilterIntf = aFilter;
? }
?
? public String filtContent(String aContent) throws ContentFilterException {
?String l_Content = aContent;
if (bodyContentFilterIntf!=null)
l_Content = bodyContentFilterIntf .filtContent(l_Content);
SendEmail(
“
webmaster@SnailWeb.com
”
,l_Content)
??? return aContext;
? }
}
當(dāng)然還有
SensitiveWordContextFilter(
過(guò)濾敏感詞匯
),HtmlContentFilter(
修飾用戶(hù)輸入留言中的超級(jí)鏈接
)
等。
有了這些過(guò)濾器,我們就可以很方便的為留言版添加各種復(fù)合的過(guò)濾器。例如我們想對(duì)輸入的留言進(jìn)行超鏈接修飾和過(guò)濾敏感詞匯,那么我們只要如下調(diào)用即可:
try {
????????? l_Content = new HtmlContentFilter(new SensitiveWordContextFilter(null)).
????????? filtContent(bodyContext);
??? }
??? catch (ContentFilterException ex) {
????? BBSCommon.showMsgInResponse(response, ex.getMessage());
?????
return;
}
我們甚至可以動(dòng)態(tài)的添加不同的過(guò)濾器,例如對(duì)于會(huì)員我們要對(duì)輸入的留言進(jìn)行超鏈接修飾并且將他的留言發(fā)送到網(wǎng)管郵箱,而對(duì)于非會(huì)員我們則要過(guò)濾他輸入的敏感詞匯并且
保證輸入的字?jǐn)?shù)不少于50,我們只要如下調(diào)用即可:
try {
???????
BodyContentFilterIntf bodyContentFilterIntf = null;
??????? bodyContentFilterIntf ?= new
HtmlContentFilter(null);
??????? if(IsMember==true)
???????????????
bodyContentFilterIntf ?= new? sendEmailContentFilter
(
bodyContentFilterIntf
);
else
???????????????
bodyContentFilterIntf ?= new?
SensitiveWordContextFilter(
bodyContentFilterIntf
);?
l_Content =
bodyContentFilterIntf.
filtContent(bodyContext);
??? }
??? catch (ContentFilterException ex) {
????? BBSCommon.showMsgInResponse(response, ex.getMessage());
????? return;
}
關(guān)于其他的設(shè)計(jì)模式的使用我在后續(xù)文章會(huì)繼續(xù)介紹,給大家推薦一個(gè)網(wǎng)站 http://www.cownew.com?,是個(gè)勵(lì)志類(lèi)的,不錯(cuò),看到它的介紹很好,很多文章是從天涯搞下來(lái)的。