职责链模式实际应用

需求背景

需 求 : 根 据 各 种 规 则 过 滤 数 据 , 筛 选 出 满 足 条 件 的 数 据 \color{red} 需求:根据各种规则过滤数据,筛选出满足条件的数据
要求:
1. 支持各种规则动态组合
2. 尽量灵活搭配,不要指定某种情景下的过滤器

代码下载

源代码下载

职责链模式

在这里插入图片描述

开发设计

  1. 定义规则过滤器顶级接口
package com.dgut.edu.com.filterproject.filterchain.filter;

/**
 * FileName: Filter
 * Author:
 * Date:     2021/6/22 19:09
 * Description: 过滤器接口
 */
public interface RuleFilter<T> {

	/**
	 * 口径过滤逻辑
	 * @param entity
	 * @return true表示可以执行下一个过滤器,false终止过滤
	 */
	boolean filter(T entity)throws Exception;

	/**
	 * 获取器的名称
	 * @return
	 */
	String name();
}

1.1 具体实现类

package com.dgut.edu.com.filterproject.filterchain.filter.impl;

import com.dgut.edu.com.filterproject.entity.PriceCompareResult;

import com.dgut.edu.com.filterproject.filterchain.filter.RuleFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * @description: 跟价口径中,商品属性过滤器,过滤掉不满足条件的数据
 * @author: hongbin.zheng
 * @create: 2021-06-28 14:39
 **/
@Slf4j
@Component
public class MerchandiseRuleFilter implements RuleFilter<PriceCompareResult> {

    private static final String MERCHANDISE_RULE_FILTER_NAME = "商品属性过滤器";

    /**
     * 1. 商品名称包含套装
     *
     * @param entity
     * @return
     * @throws Exception
     */
    @Override
    public boolean filter(PriceCompareResult entity) throws Exception {
        // 1. 过滤内网无货商品、过滤分货、过滤库存、过滤下架商品状态
        if (entity == null) {
            return true;
        }

        if (entity.getGoodsName().contains("套装")) {
            return true;
        }
        return false;


    }


    @Override
    public String name() {
        return "merchandiseRuleFilter";
    }
}

package com.dgut.edu.com.filterproject.filterchain.filter.impl;

import com.dgut.edu.com.filterproject.entity.PriceCompareResult;
import com.dgut.edu.com.filterproject.filterchain.filter.RuleFilter;

import com.dgut.edu.com.filterproject.utils.RuleFilterUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * @description: 专场过滤器
 * @author: hongbin.zheng
 * @create: 2021-06-28 17:24
 **/
@Slf4j
@Component
public class SalesNoRuleFilter implements RuleFilter<PriceCompareResult> {
    private static final String SALES_NAME_RULE_FILTER_NAME = "商品专场过滤器";

    /**
     * 2. 专场包含:专场包含VIP 和 LUX (顺序先后无关系了)
     *
     * @param entity
     * @return
     * @throws Exception
     */
    @Override
    public boolean filter(PriceCompareResult entity) throws Exception {
        // 1 专场包含VIP 和 LUX (顺序先后无关系了)
        if (RuleFilterUtils.containsWord(entity.getSalesName(), RuleFilterUtils.VIP) &&
                RuleFilterUtils.containsWord(entity.getSalesName(), RuleFilterUtils.LUX)) {
            return true;
        }
        return false;
    }

    @Override
    public String name() {
        return "salesNoRuleFilter";
    }
}

2、BusinessHandler

package com.dgut.edu.com.filterproject.filterchain.handler;

/**
 * FileName: Handler
 * Author:
 * Date:     2021/6/22 19:12
 * Description: 业务处理接口
 */
public interface BusinessHandler<T> {


	/**
	 * 处理方法
	 * @param entity
	 */
	void handler(T entity);

}

3、FilterChainConfig 过滤器配置

package com.dgut.edu.com.filterproject.filterchain;

import lombok.Data;

import java.util.List;

/**
 * FileName: FilterChainConfig
 * Author:   shangjie.tang
 * Date:     2021/6/22 20:08
 * Description: 解析配置
 */
@Data
public class FilterChainConfig {

	private String name;
	private String handler;
	private Boolean enable;
	private List<String> filterList;

}

4、 FilterChainFactory 过滤链创建工厂

package com.dgut.edu.com.filterproject.filterchain;

import com.dgut.edu.com.filterproject.filterchain.filter.RuleFilter;
import com.dgut.edu.com.filterproject.filterchain.handler.BusinessHandler;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.Map;
import java.util.Optional;

/**
 * FileName: FilterChainF
 * Author:   shangjie.tang
 * Date:     2021/6/22 20:06
 * Description: 根据配置,创建过滤链的工厂
 */
@Service
@Slf4j
public class FilterChainFactory {

	@Autowired
	private ApplicationContext context;

	private Map<String, RuleFilter> filterMap;

	private Map<String, BusinessHandler> handlerMap;


	@PostConstruct
	private void init(){
		filterMap = Maps.newHashMap();
		handlerMap = Maps.newHashMap();
		Map<String, RuleFilter> filterBeanMap = context.getBeansOfType(RuleFilter.class);
		for (Map.Entry<String, RuleFilter> entry : filterBeanMap.entrySet()) {
			filterMap.put(entry.getValue().name(),entry.getValue());
		}
		Map<String, BusinessHandler> handlerBeanMap = context.getBeansOfType(BusinessHandler.class);
		for (Map.Entry<String, BusinessHandler> entry : handlerBeanMap.entrySet()) {
			handlerMap.put(entry.getKey(),entry.getValue());
		}
	}


	public <T> FilterChain<T> createChains(FilterChainConfig config,Class<T> tClass){
		FilterChain<T> chain = new FilterChain<T>(config.getName(),handlerMap.get(config.getHandler()), Optional.ofNullable(config.getEnable()).orElse(true));
		for (String filterBeanName : config.getFilterList()) {
			RuleFilter<T> filter = filterMap.get(filterBeanName);
			if(filter!=null){
				chain.addFilter(filter);
			}
		}
		log.info("创建过滤链成功");
		return chain;
	}

}

5、过滤链 FilterChain

package com.dgut.edu.com.filterproject.filterchain;


import com.dgut.edu.com.filterproject.filterchain.filter.RuleFilter;
import com.dgut.edu.com.filterproject.filterchain.handler.BusinessHandler;
import lombok.extern.slf4j.Slf4j;

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


/**
 * FileName: BaseFilterChain
 * Author:   shangjie.tang
 * Date:     2021/6/22 19:11
 * Description: 过滤链
 */
@Slf4j
public class FilterChain<T> {

    private String name;
    private BusinessHandler<T> businessHandler;
    private List<RuleFilter<T>> chain;
    private boolean enable;

    public FilterChain(String name, BusinessHandler<T> businessHandler, boolean enable) {
        this.name = name;
        this.businessHandler = businessHandler;
        this.enable = enable;
        this.chain = new ArrayList<>();
    }

    public void addFilter(RuleFilter<T> ruleFilter) {
        this.chain.add(ruleFilter);
    }

    /**
     * 开始进行过滤
     *
     * @param entity
     * @return 通过返回原样, 不通过返回null
     * @throws Exception
     */
    public T process(T entity) throws Exception {
        if (enable && chain.size() != 0) {
            for (RuleFilter<T> ruleFilter : chain) {
                if (ruleFilter.filter(entity)) {
                    log.info("FilterChain_process-filter","没有通过该过滤器");
                    return null;
                }
            }
            //能达到这步的,都是符合业务的数据,执行业务操作
            if (businessHandler != null) {
                businessHandler.handler(entity);
            }
        } else {
            log.info("FilterChain_process-filterChain_name","过滤链没有启用");
        }
        return entity;
    }

    public String getName() {
        return name;
    }
}

6、读取配置 CfgCenterUtil

package com.dgut.edu.com.filterproject.service;

public class CfgCenterUtil {
    public static String getValue(String CfgName, String other) {
        return "[\n" +
                "\t{\n" +
                "\t\t\"name\":\"过滤链\",\n" +
                "\t\t\"handler\":\"\",\n" +
                "\t\t\"filterList\":[\"merchandiseRuleFilter\", \"salesNoRuleFilter\"]\n" +
                "\t}\n" +
                "\t\n" +
                "]";
    }
}

7、包装服务层

package com.dgut.edu.com.filterproject.service;

import com.alibaba.fastjson.JSONArray;
import com.dgut.edu.com.filterproject.entity.PriceCompareResult;
import com.dgut.edu.com.filterproject.filterchain.FilterChain;
import com.dgut.edu.com.filterproject.filterchain.FilterChainConfig;
import com.dgut.edu.com.filterproject.filterchain.FilterChainFactory;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class PcResultFilterService {
    @Autowired
    private FilterChainFactory filterChainFactory;

    /**
     * 老配置的md5
     */
    private String oldConfigMd5;

    /**
     * 生成的过滤链
     */
    private List<FilterChain<PriceCompareResult>> filterChains = new ArrayList<>();

    /**
     * 批量进行过滤
     *
     * @param priceCompareResultList
     * @return
     */
    public List<PriceCompareResult> batchExecute(List<PriceCompareResult> priceCompareResultList) {
        return priceCompareResultList.stream().filter(priceCompareResult -> execute(priceCompareResult) != null ? true : false).collect(Collectors.toList());

    }

    /**
     * 单个进行过滤
     *
     * @param result
     * @return
     */
    public PriceCompareResult execute(PriceCompareResult result) {
        checkChains();
        for (FilterChain<PriceCompareResult> filterChain : filterChains) {
            try {
                return filterChain.process(result);
            } catch (Exception e) {
                log.error("PcResultFilterAdmin_execute-filterChain", "执行失败");
            }
        }
        return result;
    }

    /**
     * 查看配置有没有更新,有就重新创建
     */
    private void checkChains() {
        try {
            String filterChainConfig = CfgCenterUtil.getValue("PC_RESULT_FILTER_CHAIN", "");
            if (StringUtils.isEmpty(filterChainConfig)) {
                log.info("checkChains-filterChainConfig", "配置为空");
                return;
            }
            String newConfigMd5 = DigestUtils.md5DigestAsHex(filterChainConfig.getBytes());
            if (!newConfigMd5.equals(oldConfigMd5)) {
                List<FilterChainConfig> configs = JSONArray.parseArray(filterChainConfig, FilterChainConfig.class);
                List<FilterChain<PriceCompareResult>> list = Lists.newArrayListWithCapacity(configs.size());
                for (FilterChainConfig config : configs) {
                    FilterChain<PriceCompareResult> chain = filterChainFactory.createChains(config, PriceCompareResult.class);
                    list.add(chain);
                }
                oldConfigMd5 = newConfigMd5;
                filterChains.clear();
                filterChains = list;
            }
        } catch (Exception e) {
            log.error("PcResultFilterAdmin_checkChains-新增或更新过滤链失败", e);
        }
    }

}

8、 测试代码

package com.dgut.edu.com.filterproject;

import com.dgut.edu.com.filterproject.entity.PriceCompareResult;
import com.dgut.edu.com.filterproject.service.PcResultFilterService;
import com.google.common.collect.Lists;
import org.junit.Assert;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class FilterprojectApplicationTests {
    @Autowired
    private PcResultFilterService pcResultFilterService;

    @Test
    void contextLoads() {
        List<PriceCompareResult> priceCompareResultLists = getPriceCompareResultLists();
        List<PriceCompareResult> priceCompareResults = pcResultFilterService.batchExecute(priceCompareResultLists);
        Assert.assertEquals(1, priceCompareResults.size());
    }

    private List<PriceCompareResult> getPriceCompareResultLists() {
        List<PriceCompareResult> results = Lists.newArrayList();
        PriceCompareResult priceCompareResult1 = getPriceCompareResult();
        results.add(priceCompareResult1);

        PriceCompareResult priceCompareResult2 = getPriceCompareResult();
        priceCompareResult2.setSalesName("专场包含VIP和LUX");
        results.add(priceCompareResult2);

        PriceCompareResult priceCompareResult3= getPriceCompareResult();
        priceCompareResult3.setGoodsName("专场套装");
        results.add(priceCompareResult3);

        return results;
    }
    private PriceCompareResult getPriceCompareResult() {
        PriceCompareResult entity = new PriceCompareResult();
        entity.setGoodsName("商品名称");
        entity.setMerchandiseNo(10086L);
        entity.setSalesName("专场名称VIP LUP");
        entity.setSalesNo(123456L);
        return entity;
    }

}

测试结果

最后效果,输入三条数据
只有一条满足,返回满足的一条,其他两天直接过滤
在这里插入图片描述

总结

知 道 的 越 多 , 不 知 道 的 越 多 , 希 望 对 你 有 帮 助 ! \color{red}知道的越多,不知道的越多,希望对你有帮助!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值