簡單用到了jdk8的Stream API,參考幾年前的文章:http://www.javashuo.com/article/p-cacuwnpu-hq.htmljava
舉個例子
一個規則有這麼多字段須要判斷: dom
工具類使用
僞代碼:ide
public boolean match() { Matchers matcher = Matchers.builder().isIgnoreNullSourceValue(true).build() .eq(sourceValue1, inputValue1) .contains(sourceList1, inputValue2); if (condition1) { matcher.eq(sourceValue2, inputValue3) .eq(sourceValue3, inputValue4) .contains(sourceList2, inputValue5); if (condition2) { matcher.eq(sourceValue4, inputValue5) .or( eq(sourceValue5, inputValue6).and(containMatch(sourceList3, inputValue7)), eq(sourceValue6, inputValue8).and(containMatch(sourceList4, inputValue9)), eq(sourceValue7, inputValue10) ); } else { // 按規則爲準,入參沒傳,但規則有配置,當不匹配 matcher.unMatch(); } } return matcher.stream().allMatch(IMatcher::match); }
具體實現
Matchers類實現:工具
package com.winning.business.clinical.rules.domain.util; import com.google.common.collect.Lists; import com.winning.base.akso.logging.core.WinLogger; import com.winning.base.akso.logging.core.WinLoggerFactory; import com.winning.pts.utils.collection.ListUtil; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; import java.util.Spliterators; import java.util.stream.Stream; import java.util.stream.StreamSupport; import static java.util.Objects.isNull; import static java.util.Objects.nonNull; /** * @author Fengqik <fqk@winning.com.cn> */ @Builder public class Matchers { private static final WinLogger LOGGER = WinLoggerFactory.getCurrentClassLogger(); /** * 是否忽略空的匹配值 */ private final boolean isIgnoreNullSourceValue; private final List<IMatcher> matchResultList = Lists.newArrayList(); private final List<List<IMatcher>> matchBundleOrList = Lists.newArrayList(); private final List<List<IMatcher>> matchBundleAndList = Lists.newArrayList(); /** * 等於匹配<br> * * @param source source * @param target target * @return this */ public Matchers eq(Object source, Object target) { if (isIgnoreNullSourceValue && isNull(source)) { // 忽略source爲空的匹配 } else { this.matchResultList.add(new EqualMatcher(source, target)); } return this; } /** * 必須進行匹配<br> * * @param source source * @param target target * @param mustMatch 是否必須判斷 * @return this */ public Matchers eq(Object source, Object target, Boolean mustMatch) { if (mustMatch) { if (nonNull(source)) { this.matchResultList.add(new EqualMatcher(source, target)); } else { this.matchResultList.add(new EqualMatcher(target, source)); } } else { this.eq(source, target); } return this; } /** * 包含匹配<br> * * @param sourceList sourceList * @param target target * @return this */ public Matchers contains(List<?> sourceList, Object target) { if (ListUtil.isNotEmpty(sourceList) && nonNull(target)) { this.matchResultList.add(new ContainMatcher(sourceList, target)); } return this; } /** * 或匹配<br> * * @return this */ public Matchers or(MatchBuilder...matchBuilders) { if (nonNull(matchBuilders)) { for (MatchBuilder matcher : matchBuilders) { this.matchBundleOrList.add(matcher.getMatcherList()); } } return this; } /** * 設置一個不匹配的校驗結果<br> * * @return this */ public Matchers unMatch() { if (LOGGER.isDebugEnabled()) { LOGGER.debug("【UN MATCH】"); } this.matchResultList.add(new NegativeMatcher()); return this; } public Stream<IMatcher> stream() { if (ListUtil.isNotEmpty(this.matchBundleOrList)) { this.matchResultList.add(new BundleOrMatcher(matchBundleOrList)); } if (ListUtil.isNotEmpty(this.matchBundleAndList)) { this.matchResultList.add(new BundleAndMatcher(matchBundleAndList)); } return StreamSupport.stream(Spliterators.spliterator(matchResultList, 0), false); } @Data @NoArgsConstructor @AllArgsConstructor static class EqualMatcher implements IMatcher { private Object matchSource; private Object matchTarget; @Override public boolean match() { boolean flag = false; if (nonNull(matchSource)) { flag = matchSource.equals(matchTarget); } else if (isNull(matchTarget)) { flag = true; } if (LOGGER.isDebugEnabled()) { LOGGER.debug("【EQ MATCH】: {} == {} ? {}", matchSource, matchTarget, flag); } return flag; } } @Data @NoArgsConstructor @AllArgsConstructor static class ContainMatcher implements IMatcher { private List<?> matchSourceList; private Object matchTarget; @Override public boolean match() { if (ListUtil.isNotEmpty(matchSourceList)) { boolean flag = matchSourceList.contains(matchTarget); if (LOGGER.isDebugEnabled()) { LOGGER.debug("【CONTAINS MATCH】: {} contains {} ? {}", matchSourceList, matchTarget, flag); } return flag; } return false; } } static class NegativeMatcher implements IMatcher { @Override public boolean match() { return false; } } @Data @AllArgsConstructor @NoArgsConstructor static class BundleOrMatcher implements IMatcher { private List<List<IMatcher>> bundleList; @Override public boolean match() { if (ListUtil.isNotEmpty(bundleList)) { return bundleList.stream().anyMatch(bundle -> { if (ListUtil.isNotEmpty(bundle)) { return bundle.stream().allMatch(IMatcher::match); } return false; }); } return false; } } @Data @AllArgsConstructor @NoArgsConstructor static class BundleAndMatcher implements IMatcher { private List<List<IMatcher>> bundleList; @Override public boolean match() { if (ListUtil.isNotEmpty(bundleList)) { return bundleList.stream().allMatch(bundle -> { if (ListUtil.isNotEmpty(bundle)) { return bundle.stream().allMatch(IMatcher::match); } return false; }); } return false; } } public interface IMatcher { /** * 匹配 * * @return true or false */ boolean match(); } @Data public static class MatchBuilder { /** * */ private final List<IMatcher> matcherList = Lists.newArrayList(); public static MatchBuilder eq(Object source, Object target) { MatchBuilder matchBuilder = new MatchBuilder(); matchBuilder.getMatcherList().add(new EqualMatcher(source, target)); return matchBuilder; } public static IMatcher eqMatch(Object source, Object target) { return new EqualMatcher(source, target); } public static IMatcher containMatch(List<?> sourceList, Object target) { return new ContainMatcher(sourceList, target); } public static MatchBuilder contain(List<?> sourceList, Object target) { MatchBuilder matchBuilder = new MatchBuilder(); matchBuilder.getMatcherList().add(new ContainMatcher(sourceList, target)); return matchBuilder; } public MatchBuilder and(IMatcher iMatcher) { this.matcherList.add(iMatcher); return this; } } }
拋磚引玉ui