设计模式 之 责任链模式学习实践

一、概述

责任链模式是行为模式的一种,它将需要触发的Handler组成一条链,
发送者将请求发给链的第一个接收者,并且沿着这条链传递,直到有一个Handler来处理它或者直到最后也没有对象处理而留在链末尾端;
责任连模式的重点是在链上,由一条链去处理相似的请求,在链中决定谁来处理这个请求。

责任链模式的角色:

  • 抽象处理者角色(Handler):该角色对请求进行抽象处理,并定义一个方法和返回下一个处理的引用。
  • 具体处理者(Concrete Handler)角色:该角色接到请求后,可以选择处理掉,或则将请求传给下一个处理则。
    由于具体处理者持有对下一个处理者的引用,因此,如果需要,可以访问下一个处理者。
  • 客户端:事件的发起者。

二、实现举例

以对字符串进行简单过滤处理为例:

  • 定义一个接口,包含一个处理方法
public interface Filter {
	String doFilter(String str);
}

  • 不同的处理过滤器,实现接口重写方法

如:

// FaceFilter.java
public class FaceFilter implements Filter {

	@Override
	public String doFilter(String str) {
		return str.replace(":)", "^V^");
	}
}
// SesitiveFilter.java
public class SesitiveFilter implements Filter {

	@Override
	public String doFilter(String str) {
		//process the sensitive words
		String r = str.replace("敏感", "和谐");
		return r;
	}

}

以及其他具体的filter。

  • FilterChain同样实现Filter,重写doFilter方法。以存放并依次执行各filter的处理
import java.util.ArrayList;
import java.util.List;

public class FilterChain implements Filter {
	List<Filter> filters = new ArrayList<Filter>();
	
	public FilterChain addFilter(Filter f) {
		this.filters.add(f);
		return this;
	}
	// 各filter依次处理
	public String doFilter(String str) {
		String r = str;
		for(Filter f: filters) {
			r = f.doFilter(r);
		}
		return r;
	}
}
  • 消息处理类
public class MsgProcessor {
	private String msg;
	public String getMsg() {
		return msg;
	}
	public void setMsg(String msg) {
		this.msg = msg;
	}
	
	/**
	 * 处理方式0:过滤项全部放在一起处理   X
	 * 不利于灵活的修改和扩展。
	 * @return
	 */
	public String process_0() {
        // 先处理带尖括号的信息  
        String r=msg.replace('<', '[')  
                    .replace('>', ']');  
          
        // 处理敏感字眼  
        r=r.replace("敏感", "和谐");  
        return r;  
	}
	
	/** 处理方式1 BEGIN**/
	// 配置需要的filter
	Filter[] filters = { new SesitiveFilter(), new FaceFilter()};
	// 按照预先配置的filter一次处理。
	public String process_1(){
        String r=msg;  
        // 处理脚本语句和敏感字眼  
        for(Filter f:filters){  
            r=f.doFilter(r);  
        }  
        return r;  
	}
	/** 处理方式1 END**/
	
	/** 处理方式2 BEGIN**/
	// 使用一个处理链
	FilterChain fc;
	public FilterChain getFc() {
		return fc;
	}
	public void setFc(FilterChain fc) {
		this.fc = fc;
	}
	public String process() {
		return fc.doFilter(msg);
	}
	/** 处理方式2 END**/
	
}
  • 测试
public class Main {

	public static void main(String[] args) {
		String msg = "<script>, 敏感信息:)";
		MsgProcessor mp = new MsgProcessor();
		mp.setMsg(msg);
		
		
		FilterChain fc = new FilterChain();
		fc.addFilter(new FaceFilter())
		  .addFilter(new SesitiveFilter());

		mp.setFc(fc);
		
		String result = mp.process();
		System.out.println(result);
	}

}

输出结果:
<script>, 和谐信息^V^

三、典型应用

Web

Servlet 和 Filter
以声明的方式插入到Http请求响应的处理过程,用于拦截请求和响应.

Netty

ChannelPieline 和 ChannelHandler
Channel的数据管道抽象为ChannelPieline,消息在ChannelPieline中流动传递,ChannelPieline持有I/O事件拦截器ChannelHandler的链表.可以通过新增和删除Handler来实现不同的业务逻辑定制.

    public void initServer() {
        unStop();
        logger.info("Attempt to init " + (ConfigUtil.IS_INNER_PROXY ? "UDP" : "TCP") + " Server!" + logTunnelInfo);
        server = ConfigUtil.IS_INNER_PROXY ? new ProxyUdpServer() : new ProxyTcpServer();
        server.setSelfPort(Integer.parseInt(channelConfig.getChannelTheEndPort()));
        server.setChannelInitializer(new ChannelInitializer<Channel>() {
            @Override
            protected void initChannel(Channel ch) throws Exception {
                ChannelPipeline channelPipeline = ch.pipeline();
                channelPipeline.addLast(ConfigUtil.IS_INNER_PROXY ? new UdpChecker(channelConfig, corral) : new TcpChecker(channelConfig, corral));
                channelPipeline.addLast(ConfigUtil.IS_INNER_PROXY ? new DatagramPacketDecoder() : new MsgDecoder());
                channelPipeline.addLast(new ProxyServerChannelHandler());
            }
        });
        server.start();
        try {
            server.bind().addListener(future -> applicationListenerManager.publishEvent(ConfigUtil.IS_INNER_PROXY ? InnerProxyToOutterProxy.class : OutterProxyToInnerProxy.class, new EnhancedParams(channelConfig, corral)));
        } catch (Exception e) {
            logger.error("Proxy " + (ConfigUtil.IS_INNER_PROXY ? "UDP" : "TCP") + " Server start failed!" + logTunnelInfo, e);
        }
    }

四、简单实践

场景描述: 某一键配置场景,需要将当前系统业务参数配置导出到Excel。
业务参数按照按不同类别写入不同的sheet页。可以把文件流作为输入,写不同sheet页作为多个Handler,后续新增配置参数或sheet页都可以很方便的修改。

  • 接口
import org.apache.poi.ss.usermodel.Workbook;
import com.tdtech.eplatform.gatekeeper.util.BusinessException;

public interface ExcelWriteHandler {
	Workbook doWriteExcel(Workbook wb) throws BusinessException;
}
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.ss.usermodel.Workbook;
import com.tdtech.eplatform.gatekeeper.util.BusinessException;

public class ExcelWriteHandlerChain implements ExcelWriteHandler{

	List<ExcelWriteHandler>  excelWriters = new ArrayList<ExcelWriteHandler>();
	
	 public ExcelWriteHandlerChain addHandler(ExcelWriteHandler eWriteHandler) {
		 this.excelWriters.add(eWriteHandler);
		 return this;
	}
	
	@Override
	public Workbook doWriteExcel(Workbook workbook) throws BusinessException {
		Workbook wb = workbook;
		for(ExcelWriteHandler excelWriter: excelWriters) {
			wb = excelWriter.doWriteExcel(wb);
		}
		return wb;
	}
}

  • 具体的某一个处理类
import java.util.List;

import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.tdtech.eplatform.gatekeeper.common.IGetAndSetConfig;
import com.tdtech.eplatform.gatekeeper.config.entity.ChannelConfig;
import com.tdtech.eplatform.gatekeeper.constant.IConfigFileSet;
import com.tdtech.eplatform.gatekeeper.util.BusinessException;
import com.tdtech.eplatform.gatekeeper.util.FileUtil;

@Service
public class ExcelWriteTunnelHandler implements ExcelWriteHandler{
	@Autowired
	private IGetAndSetConfig getconfp;
	
	@Override
	public Workbook doWriteExcel(Workbook wb) throws BusinessException {
		Sheet sheetTunnel = wb.getSheet(IConfigFileSet.sheetNameofTunnnel);
		if (sheetTunnel == null) {
			throw new BusinessException("1", "写配置文件失败");
		}
		
		List<ChannelConfig> allChannelConfig = getconfp.getAllChannelConfig();
		CellStyle style = FileUtil.getCellStyle(wb);
		int rowNum = 0;
		for (ChannelConfig channelConfig : allChannelConfig) {
			Row rows = sheetTunnel.createRow(++rowNum);
			FileUtil.setCellValue(rows, 0, style, channelConfig.getChannelName());
			FileUtil.setCellValue(rows, 1, style, channelConfig.getOppositeEndForwardVirtualIP());
			FileUtil.setCellValue(rows, 2, style, channelConfig.getOppositeEndOppositeVirtualIP());
			FileUtil.setCellValue(rows, 3, style, String.valueOf(channelConfig.getChannelTheEndPort()));
			FileUtil.setCellValue(rows, 4, style, String.valueOf(channelConfig.getChannelToEndPort()));
		}
		return wb;
	}

}
	private boolean writeEasyconfigExcel() throws BusinessException {
		boolean rst = false;
		// 读空模板文件
		ExcelReader eReader = new ExcelReader(IConfigFileSet.exportEasyconfBaseFile,IConfigFileSet.sheetNameofListenIPMapping);
		if(!eReader.isSheetExist()){
			logger.error("sheetNameofGate not exists.");
			throw new BusinessException("1", "获取一键配置文件失败。");
		}
		ExcelWriteHandlerChain handlers = new ExcelWriteHandlerChain();
		// 写网闸参数/通道参数/监听参数
		handlers.addHandler(eWriteForGate)
				.addHandler(eWriteForTunnel)
				.addHandler(eWriteForListener);
		Workbook wb = handlers.doWriteExcel(eReader.getWorkBook());
		rst = FileUtil.writeExcel(wb,IConfigFileSet.exportEasyconfFilePath);
		return rst;
	}

五、体会

所谓责任,就是一个Handler做某一种处理。各个Handler之间低耦合,易于扩展。
所谓链,就是各个Handler依次对请求做相应处理的一种组织形式。
请求者与处理者是解耦的。请求者只需要发出请求,链条中的各个具体处理者负责处理自己的那部分。
简言之就是:分离职责,动态组合。

原文地址:https://www.cnblogs.com/eaglediao/p/8133962.html