zoukankan      html  css  js  c++  java
  • 设计模式 之 责任链模式学习实践

    一、概述

    责任链模式是行为模式的一种,它将需要触发的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依次对请求做相应处理的一种组织形式。
    请求者与处理者是解耦的。请求者只需要发出请求,链条中的各个具体处理者负责处理自己的那部分。
    简言之就是:分离职责,动态组合。

  • 相关阅读:
    CSS禁止换行
    oracle时间转换:12小时24小时制
    三层架构各层次的职责
    Oracle截取字符串和查找字符串
    "......"的类型初始值设定项引发异常
    Oracle中对现有表增加列
    CSS 设置table 样式
    Aspose.Cells 根据Excel模板导出数据统计
    利用正则表达式限制网页表单里的文本框输入内容
    Table 边框 css设置
  • 原文地址:https://www.cnblogs.com/eaglediao/p/8133962.html
Copyright © 2011-2022 走看看