【代码重构设计模式之运用】之车金融产品中心基于Aviator计算引擎的应用

Aviator是一个开源的Java表达式求值器,不仅支持四则运算、三元运算、逻辑运算,而且其强大的接口支持自定义扩展函数。鉴于此,金融产品重构优化团队在金融产品平台中,选择了这个google的计算引擎,为了扩展我们业务需求,我们自定义了一系列自定义函数,以支撑我们业务场景。

####1、简单地API调用示例
第一步:我们的maven工程需要引入依赖

<!-- 表达式解析引擎 -->
<dependency>
   <groupId>com.googlecode.aviator</groupId>
   <artifactId>aviator</artifactId>
   <version>3.0.0</version>
</dependency>

第二步:通过调用AviatorEvaluator.execute的静态方法,类型返回Object类型,示例如下

import com.googlecode.aviator.AviatorEvaluator;
public class SimpleExample {
    public static void main(String[] args) {
        Long result = (Long) AviatorEvaluator.execute("1+2+3");
        System.out.println(result);
    }
}

####2、如何自定义一个函数
第一步:我们可以继承AbstractVariadicFunction,实现相应地接口。这里我们自定义一个多个数字求和的函数。

import com.googlecode.aviator.runtime.function.AbstractVariadicFunction;
import com.googlecode.aviator.runtime.function.FunctionUtils;
import com.googlecode.aviator.runtime.type.AviatorDecimal;
import com.googlecode.aviator.runtime.type.AviatorObject;

import java.math.BigDecimal;
import java.util.Map;

/**
 * @description: 多个数字求和计算(其中任何一个数字为空则作为0处理)
 * @Date : 2018/9/7 下午5:40
 * @Author : 石冬冬-Seig Heil
 */
public class SumFunction extends AbstractVariadicFunction {
    @Override
    public AviatorObject variadicCall(Map<String, Object> env, AviatorObject... args) {
        BigDecimal sum = new BigDecimal(0);
        for(AviatorObject each : args){
            if(each.getValue(env) == null){
                continue;
            }
            Number value = FunctionUtils.getNumberValue(each, env);
            sum = sum.add(new BigDecimal(value.toString()));
        }
        return new AviatorDecimal(new BigDecimal(sum.toString()));
    }

    @Override
    public String getName() {
        return "sum";
    }
}

第二步:把函数注册,并调用

AviatorEvaluator.addFunction(new SumFunction());
System.out.println(AviatorEvaluator.execute("sum(1,2)"));

####3、各种表达式类型
####3.1、三元表达式、逻辑运算

Map<String,Object> evn = new HashMap<String,Object>(){{
  put("a",3);
  put("b",2);
  put("c",5);
  put("d",-2);
}};
String expression = " (a > b) && (c > 0 || d > 0) ? a : b";
System.out.println(AviatorEvaluator.execute(expression,evn));

####3.2、各种内置函数string和math

AviatorEvaluator.execute("string.length('hello')");    // 求字符串长度
AviatorEvaluator.execute("string.contains('hello','h')");  //判断字符串是否包含字符串
AviatorEvaluator.execute("string.startsWith('hello','h')");  //是否以子串开头
AviatorEvaluator.execute("string.endsWith('hello','llo')");  是否以子串结尾

AviatorEvaluator.execute("math.pow(-3,2)");   // 求n次方
AviatorEvaluator.execute("math.sqrt(14.0)");   //开平方根
AviatorEvaluator.execute("math.sin(20)");    //正弦函数

####4、支持的数据类型
•Number类型:数字类型,支持两种类型,分别对应Java的Long和Double,也就是说任何整数都将被转换为Long,而任何浮点数都将被转换 为Double,包括用户传入的数值也是如此转换。不支持科学计数法,仅支持十进制。如-1、100、2.3等。
• String类型:字符串类型,单引号或者双引号括起来的文本串,如’helloworld’,变量如果传入的是String或者Character也将转为String类型。
• Bool类型:常量true和false,表示真值和假值,与java的Boolean.TRUE和Boolean.False对应。
• Pattern类型: 类似Ruby、perl的正则表达式,以//括起来的字符串,如/\d+/,内部实现为java.util.Pattern。
• 变量类型:与Java的变量命名规则相同,变量的值由用户传入,如"a"、“b"等
• nil类型:常量nil,类似java中的null,但是nil比较特殊,nil不仅可以参与==、!=的比较,也可以参与>、>=、<、<=的比较,Aviator规定任何类型 都n大于nil除了nil本身,nilnil返回true。用户传入的变量值如果为null,那么也将作为nil处理,nil打印为null。
####5、支持操作符
#####算术运算符
Aviator支持常见的算术运算符,包括+ - * / % 五个二元运算符,和一元运算符"-"。其中 - * / %和一元的"-“仅能作用于Number类型。 “+“不仅能用于Number类型,还可以用于String的相加,或者字符串与其他对象的相加。Aviator规定,任何类型与String相加,结果为String。
#####逻辑运算符
Avaitor的支持的逻辑运算符包括,一元否定运算符”!”,以及逻辑与的”&&",逻辑或的"||"。逻辑运算符的操作数只能为Boolean。 关系运算符
Aviator支持的关系运算符包括"<" “<=” “>” “>=” 以及"
“和”!=” 。 &&和||都执行短路规则。
关系运算符可以作用于Number之间、String之间、Pattern之间、Boolean之间、变量之间以及其他类型与nil之间的关系比较,不同类型除了nil之 外不能相互比较。
Aviator规定任何对象都比nil大除了nil之外。
#####位运算符
Aviator支持所有的Java位运算符,包括"&" “|” “^” “~” “>>” “<<” “>>>”。
#####匹配运算符
匹配运算符"=~"用于String和Pattern的匹配,它的左操作数必须为String,右操作数必须为Pattern。匹配成功后,Pattern的分组将存于变量 $num,num为分组索引。
#####三元运算符
Aviator没有提供if else语句,但是提供了三元运算符 “?:”,形式为 bool ? exp1: exp2。 其中bool必须为结果为Boolean类型的表达式,而exp1和 exp2可以为任何合法的Aviator表达式,并且不要求exp1和exp2返回的结果类型一致。
####6、为了扩展需求需求,扩展了相关函数
nvl:如果为空,设置默认值

/**
 * @description: 为空时,设置一个默认值
 * @Date : 2018/9/7 下午5:40
 * @Author : 石冬冬-Seig Heil
 */
public class Nvl extends AbstractVariadicFunction {
    @Override
    public AviatorObject variadicCall(Map<String, Object> env, AviatorObject... args) {
        Number originValue = FunctionUtils.getNumberValue(args[0], env);
        Number defaultValue = FunctionUtils.getNumberValue(args[1], env);
        return new AviatorDecimal(new BigDecimal(Optional.ofNullable(originValue).orElse(defaultValue).toString()));
    }

    @Override
    public String getName() {
        return "nvl";
    }
}

sum:多个数字求和

/**
 * @description: 多个数字求和计算(其中任何一个数字为空则作为0处理)
 * @Date : 2018/9/7 下午5:40
 * @Author : 石冬冬-Seig Heil
 */
public class Sum extends AbstractVariadicFunction {
    @Override
    public AviatorObject variadicCall(Map<String, Object> env, AviatorObject... args) {
        BigDecimal sum = new BigDecimal(0);
        for(AviatorObject each : args){
            if(each.getValue(env) == null){
                continue;
            }
            Number value = FunctionUtils.getNumberValue(each, env);
            sum = sum.add(new BigDecimal(value.toString()));
        }
        return new AviatorDecimal(new BigDecimal(sum.toString()));
    }

    @Override
    public String getName() {
        return "sum";
    }
}

min:多个数字求最小值

/**
 * @description: 多个数字求最小值(其中任何一个数字为空则作为0处理)
 * @Date : 2018/9/7 下午5:40
 * @Author : 石冬冬-Seig Heil
 */
public class Min extends AbstractVariadicFunction {
    @Override
    public AviatorObject variadicCall(Map<String, Object> env, AviatorObject... args) {
        List<BigDecimal> list = new ArrayList<>();
        for(AviatorObject each : args){
            if(each.getValue(env) == null){
                continue;
            }
            Number value = FunctionUtils.getNumberValue(each, env);
            list.add(new BigDecimal(value.toString()));
        }
        list.sort(Comparator.comparing(BigDecimal::doubleValue));
        return new AviatorDecimal(new BigDecimal(list.get(0).toString()));
    }

    @Override
    public String getName() {
        return "min";
    }
}

max:多个数字求最大值

扫描二维码关注公众号,回复: 9465002 查看本文章
/**
 * @description: 多个数字求最大值(其中任何一个数字为空则作为0处理)
 * @Date : 2018/9/7 下午5:40
 * @Author : 石冬冬-Seig Heil
 */
public class Max extends AbstractVariadicFunction {
    @Override
    public AviatorObject variadicCall(Map<String, Object> env, AviatorObject... args) {
        List<BigDecimal> list = new ArrayList<>();
        for(AviatorObject each : args){
            if(each.getValue(env) == null){
                continue;
            }
            Number value = FunctionUtils.getNumberValue(each, env);
            list.add(new BigDecimal(value.toString()));
        }
        list.sort(Comparator.comparing(BigDecimal::doubleValue).reversed());
        return new AviatorDecimal(new BigDecimal(list.get(0).toString()));
    }

    @Override
    public String getName() {
        return "max";
    }
}

round:四舍五入

/**
 * @description: 四舍五入
 * @Date : 2018/9/7 下午5:40
 * @Author : 石冬冬-Seig Heil
 */
public class Round extends AbstractVariadicFunction {
    @Override
    public AviatorObject variadicCall(Map<String, Object> env, AviatorObject... args) {
        Number value = FunctionUtils.getNumberValue(args[0], env);
        return new AviatorDecimal(Math.round(value.doubleValue()));
    }

    @Override
    public String getName() {
        return "round";
    }
}

ceil:向上取整

/**
 * @description: 向上取整
 * @Date : 2018/9/7 下午5:40
 * @Author : 石冬冬-Seig Heil
 */
public class Ceil extends AbstractVariadicFunction {
    @Override
    public AviatorObject variadicCall(Map<String, Object> env, AviatorObject... args) {
        Number value = FunctionUtils.getNumberValue(args[0], env);
        return new AviatorDecimal(Math.ceil(value.doubleValue()));
    }

    @Override
    public String getName() {
        return "ceil";
    }
}

floor:向下取整

/**
 * @description: 向下取整
 * @Date : 2018/9/7 下午5:40
 * @Author : 石冬冬-Seig Heil
 */
public class Floor extends AbstractVariadicFunction {
    @Override
    public AviatorObject variadicCall(Map<String, Object> env, AviatorObject... args) {
        Number value = FunctionUtils.getNumberValue(args[0], env);
        return new AviatorDecimal(Math.floor(value.doubleValue()));
    }

    @Override
    public String getName() {
        return "floor";
    }
}

下面的是我的公众号二维码图片,欢迎关注。
秋夜无霜

发布了46 篇原创文章 · 获赞 27 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/shichen2010/article/details/82630334