本文旨在提供一种配置化思路计算阶梯费用,更高级的做法则是通过数据库配置,注册中心等;在表达式上可以采用自定义或者spel表达式等其他方式进行处理;(代码仅展示最小demo,部分不完善orBug地方自行补充)
思路:N个区间对应N个费用模式(费用模式可以根据需要进行扩展);
先进行第一个区间的值,收集后续区间,然后按照最大区间差值加权
目录
一、核心代码
二、工具类DataCompareUtils
一、核心代码
import java.math.BigDecimal;
import java.math.MathContext;
import java.util.ArrayList;
import java.util.List;/*** description:*/
public class FeeT {public static void main(String[] args) {/*** 如果 value落在区间N,* 当前区间则为当前值减去最小值 加权计算* 剩余区间则按照区间最大值 加权计算,**/String expression = "(0,10]#(10,20]#(20,100]#(100,";String model = "*1#*2#*2#+1";String value = "101";BigDecimal bigDecimal = getStepFeeItem(expression, model, value);System.out.println(bigDecimal.doubleValue());}private static BigDecimal getStepFeeItem(String expression, String model, String value) {BigDecimal bigDecimal = new BigDecimal(0);String[] expressionArr = expression.split("#");String[] modelArr = model.split("#");List<String> expressionA = new ArrayList<>();/*** 计算第一个区间的值*/bigDecimal = computeFirst(value, bigDecimal, expressionArr, modelArr, expressionA);bigDecimal = computeLast(bigDecimal, expressionA);return bigDecimal;}private static BigDecimal computeLast(BigDecimal bigDecimal, List<String> expressionA) {for (String s : expressionA) {String[] split = s.split("#");BigDecimal computeValue = computeValue(BigDecimal.valueOf(Double.parseDouble(maxRange(split[1]))).subtract(BigDecimal.valueOf(Double.parseDouble(minRange(split[1])))), split[0]);bigDecimal = bigDecimal.add(computeValue);}return bigDecimal;}private static BigDecimal computeFirst(String value, BigDecimal bigDecimal, String[] expressionArr, String[] modelArr, List<String> expressionA) {for (int i = expressionArr.length - 1; i >= 0; i--) {if (DataCompareUtils.checkValue(value, expressionArr[i])) {BigDecimal computeValue = computeValue(BigDecimal.valueOf(Double.parseDouble(value)).subtract(BigDecimal.valueOf(Double.parseDouble(minRange(expressionArr[i])))), modelArr[i]);bigDecimal = bigDecimal.add(computeValue);//如果目标值在遍历区间,则剩余区间则放到另外一个队列中for (int j = i - 1; j >= 0; j--) {expressionA.add(new StringBuilder().append(modelArr[j]).append("#").append(expressionArr[j]).toString());}break;}}return bigDecimal;}public static String minRange(String expression) {String all = expression.replaceAll("[^0-9.,]", "");String[] split = all.split(",");return split[0];}public static String maxRange(String expression) {String all = expression.replaceAll("[^0-9.,]", "");String[] split = all.split(",");return split[1];}public static BigDecimal computeValue(BigDecimal value, String expression) {String symbol = expression.replaceAll("[^\\+\\-\\*/]", ""); //+-*/String feeValue = expression.replaceAll("[\\+\\-\\*/]", "");// 1switch (symbol) {case "+":return value.add(BigDecimal.valueOf(Double.parseDouble(feeValue))).setScale(4, BigDecimal.ROUND_CEILING);case "-":return value.subtract(BigDecimal.valueOf(Double.parseDouble(feeValue))).setScale(4, BigDecimal.ROUND_CEILING);case "*":return value.multiply(BigDecimal.valueOf(Double.parseDouble(feeValue))).setScale(4, BigDecimal.ROUND_CEILING);case "/":return value.divide(BigDecimal.valueOf(Double.parseDouble(feeValue)), MathContext.DECIMAL64).setScale(4, BigDecimal.ROUND_CEILING);default:return value;}}}
二、工具类DataCompareUtils
数据比较工具,不同区间的值进行比较
import org.apache.commons.lang3.StringUtils;import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;/*** description: 数据比较工具类*/
public class DataCompareUtils {private DataCompareUtils() {}public static final Map<String, String> SYMBOL_MAP = new HashMap<>();static {SYMBOL_MAP.put("(,)", "(,)");SYMBOL_MAP.put("[,)", "[,)");SYMBOL_MAP.put("(,]", "(,]");SYMBOL_MAP.put("[,]", "[,]");SYMBOL_MAP.put("[,", "[,");SYMBOL_MAP.put("(,", "(,");SYMBOL_MAP.put(",]", ",]");SYMBOL_MAP.put(",)", ",)");}public static final String SYMBOL_01 = "(,)";public static final String SYMBOL_02 = "[,)";public static final String SYMBOL_03 = "(,]";public static final String SYMBOL_04 = "[,]";public static final String SYMBOL_05 = "[,";public static final String SYMBOL_06 = "(,";public static final String SYMBOL_07 = ",]";public static final String SYMBOL_08 = ",)";private static final Pattern NUMBER_REG = Pattern.compile("^-?\\d+(\\.\\d+)?$");/*** 双边校验 返回true说明不符合* [4,5] (3,5)* 不符合返回false,符合区间返回true** @param value* @return*/public static boolean checkValue(String value, String config) {if (StringUtils.isEmpty(config)) {return false;}config = config.replace(" ", "").replace(",", ",").replace("(", "(").replace("【", "[").replace("】", "]").replace(")", ")").trim();config = config.replaceAll("[^0-9.()\\[\\],]", ""); //获取 [3,8]String s = config.replaceAll("[^\\[\\]\\(\\),]", "");//获取 []if (StringUtils.isEmpty(SYMBOL_MAP.get(s))) {return false;}/*** 第一个为值 第二个为配置表达式*/boolean flag = false;switch (s) {case SYMBOL_01:flag = checkLeftNoAndRightNo(value, config);break;case SYMBOL_02:flag = checkLeftAndRightNo(value, config);break;case SYMBOL_03:flag = checkLeftNoAndRight(value, config);break;case SYMBOL_04:flag = checkLeftAndRight(value, config);break;case SYMBOL_05:flag = checkLeft(value, config);break;case SYMBOL_06:flag = checkLeftNo(value, config);break;case SYMBOL_07:flag = checkRight(value, config);break;case SYMBOL_08:flag = checkRightNo(value, config);break;default:break;}return flag;}//(5,8)public static boolean checkLeftNoAndRightNo(String value, String config) {String range = config.replace("(", "").replace(")", "");String[] split = range.split(",");return checkNoIncludeMin(value, split[0]) && checkNoIncludeMax(value, split[1]);}//(5,8]public static boolean checkLeftNoAndRight(String value, String config) {String range = config.replace("(", "").replace("]", "");String[] split = range.split(",");return checkNoIncludeMin(value, split[0]) && checkIncludeMax(value, split[1]);}//[5,8)public static boolean checkLeftAndRightNo(String value, String config) {String range = config.replace("[", "").replace(")", "");String[] split = range.split(",");return checkIncludeMin(value, split[0]) && checkNoIncludeMax(value, split[1]);}//[5,8]public static boolean checkLeftAndRight(String value, String config) {String range = config.replace("[", "").replace("]", "");String[] split = range.split(",");return checkIncludeMin(value, split[0]) && checkIncludeMax(value, split[1]);}//(5,public static boolean checkLeftNo(String value, String config) {String range = config.replace("(", "").replace(",", "");return checkNoIncludeMin(value, range);}//[5,public static boolean checkLeft(String value, String config) {String range = config.replace("[", "").replace(",", "");return checkIncludeMin(value, range);}//,8)public static boolean checkRightNo(String value, String config) {String range = config.replace(")", "").replace(",", "");return checkNoIncludeMax(value, range);}//,8]public static boolean checkRight(String value, String config) {String range = config.replace("]", "").replace(",", "");return checkIncludeMax(value, range);}/*** 校验下限 不含 (6,** @param value* @param target* @return*/public static boolean checkNoIncludeMin(String value, String target) {if (StringUtils.isEmpty(value) || StringUtils.isEmpty(target)) {return false;}if (BigDecimal.valueOf(Double.parseDouble(value)).compareTo(BigDecimal.valueOf(Double.parseDouble(target))) > 0) {return true;}return false;}/*** 含最小 [6,** @param value* @param target* @return*/public static boolean checkIncludeMin(String value, String target) {if (StringUtils.isEmpty(value) || StringUtils.isEmpty(target)) {return false;}if (BigDecimal.valueOf(Double.parseDouble(value)).compareTo(BigDecimal.valueOf(Double.parseDouble(target))) >= 0) {return true;}return false;}/*** 最大包含 ,6]** @param value* @param target* @return*/public static boolean checkIncludeMax(String value, String target) {if (StringUtils.isEmpty(value) || StringUtils.isEmpty(target)) {return false;}if (BigDecimal.valueOf(Double.parseDouble(value)).compareTo(BigDecimal.valueOf(Double.parseDouble(target))) <= 0) {return true;}return false;}/*** 不含最大校验 ,6)** @param value* @param target* @return*/public static boolean checkNoIncludeMax(String value, String target) {if (StringUtils.isEmpty(value) || StringUtils.isEmpty(target)) {return false;}if (BigDecimal.valueOf(Double.parseDouble(value)).compareTo(BigDecimal.valueOf(Double.parseDouble(target))) < 0) {return true;}return false;}/*** 判断是否为数字** @param value* @return*/public static boolean checkIsNumber(String value) {return NUMBER_REG.matcher(value).matches();}//\u00A0,\u0020,\u3000
// 1.不间断空格\u00A0,主要用在office中,让一个单词在结尾处不会换行显示,快捷键ctrl+shift+space ;
//2.半角空格(英文符号)\u0020,代码中常用的;
//3.全角空格(中文符号)\u3000,中文文章中使用;public static String replaceSpecialEmpty(String value) {if (StringUtils.isEmpty(value)) {return value;}return value.replace("\\u00A0", "").replace("\\u0020", "").replace("\\u3000", "");}public static void main(String[] args) {List<String> arrayList = new ArrayList<>();arrayList.add("(5,8)");arrayList.add("[5,8)");arrayList.add("(5,8]");arrayList.add("[5,8]");arrayList.add("[5,");arrayList.add("(5,");arrayList.add(",8]");arrayList.add(",8)");String target = "8.01";for (String s : arrayList) {boolean checked = checkValue(target, s);System.out.printf("s:%s ,%s, %s", s, target, checked);System.out.println();}}}
三、效果
String expression = "(0,10]#(10,20]#(20,100]#(100,";
String model = "*1#*2#*2#+1";
String value = "101";
1+80*2+10*2+10
1+160+20+10=191