本文旨在提供一种配置化思路计算阶梯费用,更高级的做法则是通过数据库配置,注册中心等;在表达式上可以采用自定义或者spel表达式等其他方式进行处理;(代码仅展示最小demo,部分不完善地方自行补充)
思路: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,
* 当前区间则为当前值减去最小值 加权计算
* 剩余区间则按照区间最大值 加权计算,
* 1 10 80 -1
*/
String expression = "(0,10]#(10,20]#(20,100]#(100,";
String model = "+1#*1#*1#-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], true);
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], true);
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, boolean flag) {
String symbol = expression.replaceAll("[^\\+\\-\\*/]", ""); //+-*/
String feeValue = expression.replaceAll("[\\+\\-\\*/]", "");// 1
switch (symbol) {
case "+":
return flag ? BigDecimal.valueOf(Double.parseDouble(feeValue)).setScale(4, BigDecimal.ROUND_CEILING) : value.add(BigDecimal.valueOf(Double.parseDouble(feeValue))).setScale(4, BigDecimal.ROUND_CEILING);
case "-":
return flag ?BigDecimal.valueOf(Double.parseDouble(feeValue)).multiply(BigDecimal.valueOf(-1)).setScale(4, BigDecimal.ROUND_CEILING): 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