1. 程式人生 > >責任鏈設計模式(過濾器/攔截器)

責任鏈設計模式(過濾器/攔截器)

       責任鏈設計模式(Chain of Responsibility)的應用有:Java Web中的過濾器鏈、springmvc中的攔截器鏈,Struts2中的攔截器棧等等。

       先看如下一個問題:

       給定一個字串“被就業了:),敏感資訊,<script>”,對其中的HTML標記和敏感詞進行過濾或替換。本文主要以該問題設計方法的演變來講解責任鏈設計模式。

第一種設計:沒有任何設計模式

       設計了一個MsgProcessor類,完成字串處理的主要工作。MainTest類是本設計中的測試類。

package zmx.designmode.test.responsibilitychain;

public class MainTest {
	
	public static void main(String[] args) {
		
	        //需要被過濾的語句  
	        String msg = "被就業了:),敏感資訊,<script>";  
	        //例項化處理類  
	        MsgProcessor mp = new MsgProcessor(msg);  
	        String r = mp.process();  
	        System.out.println(r);	
	}

}
package zmx.designmode.test.responsibilitychain;

public class MsgProcessor {

	private String msg;

	public MsgProcessor(String msg) {
		this.msg = msg;
	}

	public String process() {
		String r = msg;
		// 過濾msg中的HTML標記
		r = r.replaceAll("<.*>", "");
		
		// 過濾敏感詞
		r = r.replace("敏感資訊", "").replace("被就業", "就業");
		return r;
	}

}

測試結果:

        就業了:)

       在第一種設計中,對字串的所有處理都放在MsgProcessor類中,擴充套件性極差。如果要過濾字串中的笑臉(將”:)”替換成”^_^”),則需要改動MSgProcessor中的process方法。我們看第二種設計。

第二種設計:增加一個Filter介面

1、filter介面:

package zmx.designmode.test.responsibilitychain;

public interface Filter {
	
	public String doFilter(String str);

}

2、定義實現幾種實現:

package zmx.designmode.test.responsibilitychain;

public class HtmlFilter implements Filter {

	@Override
	public String doFilter(String str) {
		
        String r = str;  
        //過濾msg中的HTML標記  
        r = r.replaceAll("<.*>", "");  
        return r;  

	}

}
package zmx.designmode.test.responsibilitychain;

public class SensitiveFilter implements Filter {

	@Override
	public String doFilter(String str) {
		
        String r = str;  
        //過濾str中的敏感資訊 
        r = r.replace("敏感資訊", "").replace("被就業", "就業");
		return r;  

	}

}


3、處理類

package zmx.designmode.test.responsibilitychain;

public class MsgFilterProcessor {
	
	private String msg;
	private Filter[] filters= new Filter[]{new HtmlFilter(),new SensitiveFilter()};
	
	public MsgFilterProcessor(String msg) {
		this.msg = msg;
	}
	
	public String process(){
		
        String r = msg;  
        for(Filter f : filters){  
	        r = f.doFilter(r);  
        }  
        return r;  

	}

}


4、測試類

package zmx.designmode.test.responsibilitychain;

public class MainTest {
	
	public static void main(String[] args) {
		
	        //需要被過濾的語句  
	        String msg = "被就業了:),敏感資訊,<script>";  
	        //例項化處理類  
	        //MsgProcessor mp = new MsgProcessor(msg);  	        
	        MsgFilterProcessor mp = new MsgFilterProcessor(msg);
	        String r = mp.process();  
	        System.out.println(r);	
	}

}


測試結果:

        就業了:)

        此時,如果需要過濾字串中的笑臉,只需要建立一個類FaceFilter實現Filter介面,並在MsgProcessor類中的filters欄位中登記即可。

第三種設計:責任鏈模式(FilterChain)

       定義:將一個事件處理流程分派到一組執行物件上去,這一組執行物件形成一個鏈式結構,事件處理請求在這一組執行物件上進行傳遞。責任鏈模式的主要參與角色:

       ① 事件處理請求物件(Request)

       ② 執行物件(Handler)

責任鏈設計模式(過濾器、攔截器)1838

1、FilterChain

package zmx.designmode.test.responsibilitychain;

import java.util.ArrayList;
import java.util.List;

public class FilterChain implements Filter {
	
	public List<Filter> filters = new ArrayList<Filter>();
	
	public FilterChain addFilter(Filter f){
		filters.add(f);  
	    return this;
	}

	@Override
	public String doFilter(String str) {
		
        String r = str;  
        for(Filter f : filters){  
	        r = f.doFilter(r);  
        }  
        return r; 

	}

}

2、SimleFilter

package zmx.designmode.test.responsibilitychain;

public class SmileFilter implements Filter {

	@Override
	public String doFilter(String str) {
		
        String r = str;  
        //過濾msg中的笑臉標記  
        r = r.replace(":)", "^_^");  
        return r;  

	}

}


3、MsgFilterChainProcessor

package zmx.designmode.test.responsibilitychain;

public class MsgFilterChainProcessor {
	
    private String msg;  
    private FilterChain chain = new FilterChain();  
    public MsgFilterChainProcessor(String msg, FilterChain filterChain){  
        this.msg = msg;  
        this.chain = filterChain;  
    }  
    public String process(){  
        return chain.doFilter(msg);  
    } 


}

4、MainTest

package zmx.designmode.test.responsibilitychain;

public class MainTest {
	
	public static void main(String[] args) {
		
	        //需要被過濾的語句  
	        String msg = "被就業了:),敏感資訊,<script>";  
	        //例項化處理類  
	        //MsgProcessor mp = new MsgProcessor(msg);  	        
	        //MsgFilterProcessor mp = new MsgFilterProcessor(msg);
	        
	        //搞一個過過濾鏈  
	        FilterChain chain = new FilterChain();  
	        chain.addFilter(new HtmlFilter())
	             .addFilter(new SensitiveFilter())
	             .addFilter(new SmileFilter());  
	        //例項化處理類  
	        MsgFilterChainProcessor mp = new MsgFilterChainProcessor(msg,chain);

	        String r = mp.process();  
	        System.out.println(r);	
	}

}


測試結果:

     就業了^_^

責任鏈模式加強版

      上面的實現的過濾鏈可以用下圖a)表示出來,整個過程只對msg過濾了一次。而JavaWeb中的過濾器鏈和Struts2中的攔截器棧執行的過程可以形象的表示為圖b,很重要)。

責任鏈設計模式(過濾器、攔截器)2890

       下面用程式模擬JavaWeb中的過濾器,實現類似於對Request和Response的過濾。主要涉及的類如下所示:

責任鏈設計模式(過濾器、攔截器)2950

public interface Filter {
    void doFilter(Request req,Response resp,FilterChain chain);
}
public class HtmlFilter implements Filter {
    public void doFilter(Request req, Response resp, FilterChain chain) {
        //過濾req.reqStr中的HTML標記
        req.reqStr = req.reqStr.replace("<", "<").replace(">", ">");
        req.reqStr += "---HtmlFilter()---";
        chain.doFilter(req, resp);
        resp.respStr += "---HtmlFilter()---";
    }
}
public class SensitiveFilter implements Filter {
    public void doFilter(Request req, Response resp, FilterChain chain) {
        // 過濾req.reqStr中的敏感詞
        req.reqStr = req.reqStr.replace("敏感", "").replace("被就業", "就業");
        req.reqStr += "===SensitiveFilter";
        chain.doFilter(req, resp);
        resp.respStr += "===SensitiveFilter";
    }
}
public class FilterChain{
    private List<Filter> filters = new ArrayList<Filter>();
    //呼叫鏈上的過濾器時,記錄過濾器的位置用
    private int index = 0;
    public FilterChain addFilter(Filter f){
        filters.add(f);
        return this;
    }
    public void doFilter(Request req, Response resp) {
        if(index == filters.size()) return;
        //得到當前過濾器
        Filter f = filters.get(index);
        index++;
        f.doFilter(req, resp, this);
    }
}
public class Request {
    //在Request中只保持了一個reqStr欄位記錄對Request的操作
    //為了方便模擬,沒有將reqStr設定為private
    String reqStr;
}
 
public class Response {
    //在Response中只保持了一個respStr欄位記錄對Response的操作
    //為了方便模擬,沒有將respStr設定為private
    String respStr;
}
package org.flyne.fiter;
public class MainClass {
    public static void main(String[] args) {
        // 需要被過濾的語句
        String msg = "被就業了:),敏感資訊,<script>";
        //建立Request、Response物件
        Request req = new Request();
        Response resp = new Response();
        req.reqStr = msg;
        resp.respStr = "response";
        //搞一個過濾鏈,鏈上有兩個過濾器
        FilterChain chain = new FilterChain();
        chain.addFilter(new HtmlFilter())
             .addFilter(new SensitiveFilter());
        //開始過濾
        chain.doFilter(req, resp);
        System.out.println(req.reqStr);
        System.out.println(resp.respStr);
    }
}