責任鏈模式

1.定義xss

在責任鏈模式裏,不少對象由每個對象對其下家的引用而鏈接起來造成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個對象決定處理此請求。發出這個請求的客戶端並不知道鏈上的哪個對象最終處理這個請求,這使得系統能夠在不影響客戶端的狀況下動態地從新組織和分配責任。ide

 

2.問題和解決方案性能

擊鼓傳花是一種熱鬧而又緊張的飲酒遊戲。在酒宴上賓客依次坐定位置,由一人擊鼓,擊鼓的地方與傳花的地方是分開的,以示公正。開始擊鼓時,花束就開始依次傳遞,鼓聲一落,若是花束在某人手中,則該人就得飲酒。ui

  好比說,賈母、賈赦、賈政、賈寶玉和賈環是五個參加擊鼓傳花遊戲的傳花者,他們組成一個環鏈。擊鼓者將花傳給賈母,開始傳花遊戲。花由賈母傳給賈赦,由賈赦傳給賈政,由賈政傳給賈寶玉,又賈寶玉傳給賈環,由賈環傳回給賈母,如此往復,以下圖所示。當鼓聲中止時,手中有花的人就得執行酒令。this

 擊鼓傳花即是責任鏈模式的應用。責任鏈多是一條直線、一個環鏈或者一個樹結構的一部分。編碼

 

3.結構.net

一個典型的對象結構可能以下圖所示調試

code

抽象處理者角色(Handler:Approver):定義一個處理請求的接口,和一個後繼鏈接(可選)。若是須要,接口能夠定義出一個方法以設定和返回對下家的引用。這個角色一般由一個Java抽象類或者Java接口實現。上圖中Handler類的聚合關係給出了具體子類對下家的引用,抽象方法handleRequest()規範了子類處理請求的操做。對象

具體處理者角色(ConcreteHandler:President):處理它所負責的請求,能夠訪問後繼者,若是能夠處理請求則處理,不然將該請求轉給他的後繼者。

客戶類(Client):向一個鏈上的具體處理者ConcreteHandler對象提交請求

抽象處理者角色

public abstract class Handler {  
  
    /** 
     * 下一級責任鏈 
     */  
    protected Handler successor;  
  
    /** 
     * 示意處理請求的方法,雖然這個示意方法是沒有傳入參數的 但實際是能夠傳入參數的,根據具體須要來選擇是否傳遞參數 
     */  
    public abstract void handleRequest();  
  
    /** 
     * 取值方法 
     */  
    public Handler getSuccessor() {  
        return successor;  
    }  
  
    /** 
     * 賦值方法,設置下一級責任鏈
     */  
    public void setSuccessor(Handler successor) {  
        this.successor = successor;  
    }  
  
}

具體處理者角色

public class ConcreteHandler extends Handler {  
    /** 
     * 處理方法,調用此方法處理請求 
     */  
    @Override  
    public void handleRequest() {  
        /** 
         * 判斷是否有後繼的責任對象 若是有,就轉發請求給後繼的責任對象 若是沒有,則處理請求 
         */  
        if (getSuccessor() != null) {  
            System.out.println("放過請求");  
            getSuccessor().handleRequest();  
        } else {  
            System.out.println("處理請求");  
        }  
    }  
  
}

客戶端類

public class Client {  
  
    public static void main(String[] args) {  
        // 組裝責任鏈  
        Handler handler1 = new ConcreteHandler();  
        Handler handler2 = new ConcreteHandler();  
        handler1.setSuccessor(handler2);  
        // 提交請求  
        handler1.handleRequest();  
    } 
}

      能夠看出,客戶端建立了兩個處理者對象,並指定第一個處理者對象的下家是第二個處理者對象,而第二個處理者對象沒有下家。而後客戶端將請求傳遞給第一個處理者對象。

  因爲本示例的傳遞邏輯很是簡單:只要有下家,就傳給下家處理;若是沒有下家,就自行處理。所以,第一個處理者對象接到請求後,會將請求傳遞給第二個處理者對象。因爲第二個處理者對象沒有下家,因而自行處理請求。

 

4.應用場景

過濾器接口

public abstract class Filter {
    //request 和response在真正的servlet中是對象,此處簡化處理爲string
    public abstract void doFilter(String request,String response,FilterChain filterChain);
}

過濾器-處理字符集

public class EncodeFilter extends Filter {

    @Override
    public void doFilter(String request, String response, FilterChain filterChain) {
        System.out.println("對request作utf-8編碼");
        filterChain.doFilter(request, response);
        System.out.println("對response作utf-8編碼");
    }

}

過濾器-處理xss攻擊

public class XssFilter extends Filter {

    @Override
    public void doFilter(String request, String response, FilterChain filterChain) {
        System.out.println("過濾request的xss內容");
        filterChain.doFilter(request, response);
        System.out.println("過濾response的xss內容");
    }

}

servlet接口,僅實現service接口

public interface Servlet {
    public void service(String request,String response);
}

定義一個servlet實現

public class MainServlet implements Servlet {

    @Override
    public void service(String request, String response) {
        System.out.println(request);
                //爲response賦值
        response="返回結果";
        System.out.println(response);
    }
}

定義內部處理的filter鏈,鏈中保存真正filter的執行順序,和servlet

public class FilterChain {
    private int cursor;
    public List<Filter> filters=new ArrayList<Filter>();
    public Servlet servlet;
    public void setServlet(Servlet servlet){
        this.servlet=servlet;
    }
    public void addFilter(Filter filter){
        this.filters.add(filter);
    }
    
    
    public void doFilter(String request,String response){
        if(cursor<filters.size()){
            filters.get(cursor++).doFilter(request, response,this);
        }else {
            servlet.service(request, response);
        }
    }
}

客戶端代碼

public class Client {
    public static void main(String[] args) {
        //定義filter
        Filter encodeFilter=new EncodeFilter();
        Filter xssFilter=new XssFilter();
        FilterChain chain=new FilterChain();
        chain.addFilter(encodeFilter);
        chain.addFilter(xssFilter);
        
        //定義servlet
        Servlet servlet=new MainServlet();
        chain.setServlet(servlet);
        chain.doFilter("發送請求", "");
    }
}

處理結果

對request作utf-8編碼
過濾request的xss內容
發送請求
返回結果
過濾response的xss內容
對response作utf-8編碼

 

5.優缺點

優勢

     下降耦合度 :該模式使得一個對象無需知道是其餘哪個對象處理其請求。對象僅需知道該請求會被「正確」地處理。接收者和發送者都沒有對方的明確的信息,且鏈中的對象不需知道鏈的結構。

     職責鏈可簡化對象的相互鏈接 :    結果是,職責鏈可簡化對象的相互鏈接。它們僅需保持一個指向其後繼者的引用,而不需保持它全部的候選接受者的引用。

     加強了給對象指派職責( R e s p o n s i b i l i t y )的靈活性 :當在對象中分派職責時,職責鏈給你更多的靈活性。你能夠經過在運行時刻對該鏈進行動態的增長或修改來增長或改變處理一個請求的那些職責。你能夠將這種機制與靜態的特例化處理對象的繼承機制結合起來使用。

增長新的請求處理類很方便

缺點

      不能保證請求必定被接收。既然一個請求沒有明確的接收者,那麼就不能保證它必定會被處理 —該請求可能一直到鏈的末端都得不處處理。一個請求也可能因該鏈沒有被正確配置而得不處處理。

     系統性能將受到必定影響,並且在進行代碼調試時不太方便;可能會形成循環調用。

 

6.總結

      在職責鏈模式裏,不少對象由每個對象對其下家的引用而鏈接起來造成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個對象決定處理此請求。發出這個請求的客戶端並不知道鏈上的哪個對象最終處理這個請求,這使得系統能夠在不影響客戶端的狀況下動態地從新組織鏈和分配責任。

      職責鏈模式的主要優勢在於能夠下降系統的耦合度,簡化對象的相互鏈接,同時加強給對象指派職責的靈活性,增長新的請求處理類也很方便;其主要缺點在於不能保證請求必定被接收,且對於比較長的職責鏈,請求的處理可能涉及到多個處理對象,系統性能將受到必定影響,並且在進行代碼調試時不太方便。

參考:

http://blog.csdn.net/m13666368773/article/details/7702368

http://blog.csdn.net/hguisu/article/details/7547231

相關文章
相關標籤/搜索