<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    零全零美(www.zzgwt.com)
    生活中的很多事情,并不像If...Else那么簡單!
    posts - 96,comments - 52,trackbacks - 0

    版權聲明:可以任意轉載,轉載時請務必以超鏈接形式標明文章原始出處和作者信息及本聲明
    英文原文地址:
    http://dev2dev.bea.com/pub/a/2005/05/decorators.html

    中文地址
    http://www.matrix.org.cn/resource/article/43/43603_Servlet_Request.html

    關鍵詞:Servlet  Request    filter  Decorator


    摘要
    裝飾模式是Erich  Gamma等人所著的《設計模式:可利用面向對象軟件的基礎》一書中眾多模式之一。一般來說,此模式在設計Swing的程序員中比較流行,他們用它來改進軟件。今天,即使有許多程序是基于Web應用的,裝飾模式仍有用武之地,在J2EE的環境下也有使用的價值。
    本文說明了如何將裝飾模式應用到servlet  request對象上。首先,提出了一個與servlet  filter有關的問題,并解釋了隨之而引入的裝飾模式。然后,討論了如何在servlet環境下使用此模式,并列出了使用此模式的幾個比較有名的基于servlet的項目。最后,文章通過實現一個刪除空白符的filter例子,演示了裝飾模式在servlet中的使用。

    簡介
           Servlet規范中所引入的filter令人心動不已,因為它引入了一個功能強大的攔截模式。Filter是這樣一種Java對象,它能在request到達servlet的服務方法之前攔截HttpServletRequest對象,而在服務方法轉移控制后又能攔截HttpServletResponse對象。你可以使用filter來實現特定的任務,比如驗證用戶輸入,以及壓縮web內容。但你擬富有成效地使用過濾器的念頭卻被你不能改變HttpServletRequest對象的參數的現實掃了興,因為java.util.Map所包裝的HttpServletRequest對象的參數是不可改變的。這極大地縮減了filter的應用范圍。至少在一半的時間里,你希望可以改變準備傳送給filter的對象。如果在HttpServletRequest對象到達Struts的action  servlet之前,我們可以通過一個filter將用戶輸入的多余空格去掉,難道不是更美妙嗎?這樣的話,你就不必等到在Struts的action表單驗證方法中才進行這項工作了。
    幸運的是,盡管你不能改變不變對象本身,但你卻可以通過使用裝飾模式來改變其狀態。

    裝飾模式
    在繼承中,你可以通過繼承一個父類并覆蓋你希望改變的方法來改變對象狀態。然而,如果這個對象是由程序的另一個子模塊,例如對象工廠  (這里所說的工廠是工廠模式中的術語,下同。譯者注)  或是servlet容器所產生的,繼承就無能為力了。
    裝飾模式可用來增加一個現有對象的功能,或是改變其狀態。與其使用繼承方式來擴展此類,這個模式將一個對象包裝成另外一個對象。圖1是裝飾模式的UML類圖。


    圖1:裝飾模式


    在圖1中,Component是一個接口,其具體實現是ConcreteComponent。要改變Component的狀態,你可以修改ConcreteComponent或是擴展它  (通過繼承或實現接口的方式,譯者注)。然而,如果ConcreteComponent來自于一個工廠,你卻無計可施。你所能做的,就是創建一個同為實現了Component接口的裝飾類。在圖1中,這個裝飾類的角色就由Decorator來扮演,在程序中通常表現為接口或抽象類。Decorator類的一個特性就是,它有一個接收Component對象的構造方法。你將擬裝飾的對象傳遞給這個構造方法。在本例中,這個對象就是從工廠獲得的ConcreteComponent對象。通過將此裝飾對象傳遞給Decorator的一個類變量,你可以訪問Decorator中的任何方法。這就使你得以改變對象的狀態了。
    圖1中的Decorator類不一定是接口或抽象類。如果你的程序不是很復雜,你可以將其轉化為一個具體的Decorator類。
    舉個例子,考慮這樣一個簡單的消息傳遞程序,其主要部分是Messenger接口及其實現類MessengerImpl。讓我們假設MessengerImpl對象來自于一個工廠,因此你不能改變其狀態。如果你準備增加或改變Messenger對象的功能,你可以創建一個MessengerDecorator類。圖2是此例子的類圖。



    圖2:Messenger裝飾類


    我們來看程序的代碼。列表1給出了Messenger接口的代碼,列表2是MessengerImpl類的代碼。

    列表1:Messenger接口


    public  interface  Messenger  {    public  String  getMessage();}


    列表2:MessengerImpl類

    public class MessengerImpl implements Messenger {
        
    private String message;

        
    public MessengerImpl(String message) {
            
    this.message = message;
        }


        
    public String getMessage() {
            
    return message;
        }

    }


    Messenger對象由一個名為MessengerFactory的工廠創建,如列表3所示。

    列表3:MessengerFactory類

    public  class  MessengerFactory  {    public  static  Messenger  getMessenger()  {        return  new  MessengerImpl("secrets");    }}


    對每一個所創建的Messenger對象,此工廠通過某個未知的操作,初始化了getMessage()方法所返回的字符串。換句話說,你不能自己創建Messenger對象。
    在程序中,Messenger對象的主要用途是被傳遞給一個名為Util的類中的broadcast()靜態方法。列表4是Util類的代碼。

    列表4:Util類

    public  class  Util  {    public  static  void  broadcast(Messenger  messenger)  {        System.out.print(messenger.getMessage());    }    //  other  methods  here}


    在你自己的類中,你可能會有這樣的代碼:

    Messenger  messenger  =  MessengerFactory.getMessenger();Util.broadcast(messenger);


    假設你希望對broadcast()方法所打印出的消息做一小改動。你擬將其轉為大寫,怎么做?表面上看,你可以繼承Messenger,實例化其子類,并將返回的對象傳給Util.broadcast()。但是,這種做法毫無意義,因為只有工廠才知道如何初始化Messenger對象,并通過其getMessage()方法返回正確的值。
    使用裝飾模式,你可以創建一個MessengerDecorator類,如列表5所示。

    列表5:MessengerDecorator類

    public  class  MessengerDecorator  implements  Messenger  {    private  Messenger  messenger;    public  MessengerDecorator(Messenger  messenger)  {        this.messenger  =  messenger;    }    public  String  getMessage()  {        return  messenger.getMessage().toUpperCase();    }}


    因為MessengerDecorator實現了Messenger,Util.broadcast()將接受一個MessengerDecorator的實例。然而,MessengerDecorator不僅僅是一個接口的實現,它還是一個MessengerImpl對象的裝飾器。正因如此,MessengerDecorator就必須有一個接收擬被裝飾的Messenger對象的構造方法。
    如列表5所示,這個構造方法將參數傳給變量。你現在可以覆蓋MessengerDecorator中的getMessage()方法,以便將消息轉為大寫后再打印出來。因為你持有原來Messenger對象的引用,你可以這樣寫getMessage()方法:

    public  String  getMessage()  {    return  this.messenger.getMessage().toUpperCase();}


    MessengerDecorator中的getMessage()方法返回原始消息的大寫版本。
    在你的類中,就像往常一樣,你得到一個Messenger對象,并將Decorator傳給Util.broadcast()。

    Messenger  messenger  =  factory.getMessenger();Util.broadcast(new  MessengerDecorator(messenger));


    你并不將原始對象傳給原先的目標,相反,你將其傳給了該對象的裝飾器。

    應用裝飾模式于Servlet
    以上Messenger類的例子與servlet容器所構造的ServletRequest對象是一樣的。當收到一個HTTP請求時,servlet容器就會創建ServletRequest對象及ServletResponse對象(分別是ServletRequestImpl及ServletResponseImpl的實例),并將這兩個對象傳遞給特定的servlet服務方法。現在,如果你為ServletRequest創建一個裝飾角色,并將其傳給servlet服務方法,你就應用了裝飾模式。
    對ServletRequest很容易應用裝飾模式,因為servlet  API已經為其提供了一個包裝類:ServletRequestWrapper。圖3是一個servlet裝飾模式的類圖。

    圖3:Servlet  API中的裝飾模式


    圖3中的HTTP版本的類圖如圖4所示。別為過多的類搞暈了頭,只管注意虛線框中的三個類就行了:HttpServletRequest,  HttpServletRequestImpl,  HttpServletRequestWrapper。

    圖4:Servlet  API  (HTTP)的裝飾模式


    情況與前面所舉例子類似。你擁有一個ServletRequest的實現,而它是由servlet容器產生的。你可以使用所提供的ServletRequestWrapper來裝飾這些ServletRequest對象。
    這個模式很簡單,在實際應用中可以派上用場。實際上,一些很有名的應用就使用了此模式。這些應用包括:
                   Struts  -  Struts是當前開發Java  Web應用最受歡迎的基于MVC(模型-視圖-控制)模式的框架。Struts提供了相當于ServletRequest包裝類的org.apache.struts.upload.MultipartRequestWrapper類。  MultipartRequestWrapper覆蓋了getParameter(),getParameterNames(),及getParameterValues()等方法來實現文件上傳。
                   Apache  Beehive  ?C  這個源于BEA的WebLogic專題小組的開源項目,構建于Struts之上,并簡化了web應用及web服務的開發。與ServletRequest包裝類一樣,org.apache.beehive.netui.pageflow.internal包中的PageFlowRequestWrapper類有助于任意Apache  Beehive應用的頁流處理。
    現在,讓我們來看看,如何編寫自己的HttpServletRequest裝飾類。

    一個刪除空白字符的Filter
    本節將以上的理論投入實際使用,通過實現一個刪除空白字符的filter,來演示如何使用javax.servlet.http.HttpServletRequestWrapper類來裝飾HttpServletRequest對象。在本例中,這個filter將刪除所傳來的參數中多余的空白字符。
    這在許多servlet/JSP應用中是很有用的,包括Struts及JavaServer  Faces等應用。例如,Struts通過調用HttpServletRequest對象的getParameterValues()對象來處理action表單。通過覆蓋裝飾類中此方法,你可以改變當前HttpServletRequest對象的狀態。
    要創建HttpServletRequest的裝飾類,你需要繼承HttpServletRequestWrapper并且覆蓋你希望改變的方法。列表5中,MyRequestWrapper類將刪除getParameterValues()方法返回值的多余空白字符。

    列表5:HttpServerletRequest裝飾類

     

    package trimmer.filter;

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;

    public final class MyRequestWrapper extends HttpServletRequestWrapper {
        
    public MyRequestWrapper(HttpServletRequest servletRequest) {
            
    super(servletRequest);
        }


        
    public String[] getParameterValues(String parameter) {
            String[] results 
    = super.getParameterValues(parameter);
            
    if (results == null)
                
    return null;
            
    int count = results.length;
            String[] trimResults 
    = new String[count];
            
    for (int i = 0; i < count; i++{
                trimResults[i] 
    = results[i].trim();
            }

            
    return trimResults;
        }

    }


    列表6演示了如何載獲Http請求并裝飾HttpServletRequest對象。[i]列表6:刪除空白符的filter


    列表6演示了如何載獲Http請求并裝飾HttpServletRequest對象。

    [i]列表6:刪除空白符的filter

    package trimmer.filter;

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;

    public final class MyRequestWrapper extends HttpServletRequestWrapper {
        
    public MyRequestWrapper(HttpServletRequest servletRequest) {
            
    super(servletRequest);
        }


        
    public String[] getParameterValues(String parameter) {
            String[] results 
    = super.getParameterValues(parameter);
            
    if (results == null)
                
    return null;
            
    int count = results.length;
            String[] trimResults 
    = new String[count];
            
    for (int i = 0; i < count; i++{
                trimResults[i] 
    = results[i].trim();
            }

            
    return trimResults;
        }

    }

    這個程序使用了列表6所示的filter來修整用戶輸入。要使用這個filter,你需要在web.xml文件中如下設置filter及filter-mapping的元素。
       
     <filter>
           <filter-name>TrimmerFilter</filter-name>
           <filter-class>trimmer.filter.MyFilter</filter-class>
       </filter>
       <filter-mapping>
           <filter-name>TrimmerFilter</filter-name>
           <url-pattern>*.do</url-pattern>
       </filter-mapping>


    要測試這個filter,啟動這個應用后,在表單中輸入一些值,提交表單,看看這個filter是如何修整輸入數值的。這是一個實用的裝飾模式的應用。

    小結
    Servlet  filter可以在調用一個servlet的服務方法后,攔載或加工HTTP請求。盡管這非常誘人,但其實際使用卻有所限制,因為你不能改變HttpServletRequest對象。
    這時候裝飾模式派上了用場。本文演示了如何通過應用裝飾模式來“修改”HttpServletRequest對象,從而使你的servlet  filter更加有用。在上面filter例子中,filter改了request參數中的用戶輸入,而這一點,如果沒有裝飾request對象,你是無論如何也不可能做到的。

    Budi  Kurniawan是一個高級J2EE的架構師。他還是《Tomcat如何工作:教你如何開發自己的Servlet容器》  (”How  Tomcat  Works:  A  Guide  to  Developing  Your  Own  Servlet  Container”)  以及《Struts設計與編程指南》(”Struts  Design  and  Programming  :A  Tutorial”)  這兩本書的作者,它們均由BrainySoftwar.com出版。
    posted on 2009-11-24 11:21 零全零美 閱讀(631) 評論(0)  編輯  收藏 所屬分類: 設計模式
    主站蜘蛛池模板: 亚洲一卡2卡三卡4卡无卡下载| 84pao国产成视频免费播放| 亚洲冬月枫中文字幕在线看| 国产亚洲色视频在线| 成人免费视频小说| 120秒男女动态视频免费| 国产中文字幕在线免费观看| 亚洲.国产.欧美一区二区三区| 亚洲成无码人在线观看| 亚洲国产人成网站在线电影动漫 | 亚洲综合精品香蕉久久网97| 亚洲日韩中文在线精品第一 | 中文字幕亚洲精品无码| 亚洲国产精品久久久久网站 | 亚洲视频在线免费| 国产精品久久久久久亚洲小说| 亚洲伦理中文字幕| 亚洲婷婷综合色高清在线| 亚洲最新永久在线观看| 亚洲视频2020| 久久亚洲成a人片| 国产成A人亚洲精V品无码 | 中文在线免费看视频| 老外毛片免费视频播放| 亚洲6080yy久久无码产自国产| 亚洲精品乱码久久久久久V | 全黄a免费一级毛片人人爱| 四虎影视免费在线| 好大好硬好爽免费视频| 啦啦啦高清视频在线观看免费| 免费看美女裸露无档网站| 色老头永久免费网站| 可以免费看黄的网站| 精品久久久久国产免费| 97热久久免费频精品99| 国产在线a免费观看| 成年女性特黄午夜视频免费看| 精品免费国产一区二区| 国产zzjjzzjj视频全免费| 亚洲国产成人精品女人久久久| 亚洲精品专区在线观看|