在代码中写死业务计算公式与计算公式模板中选择了与

某天,领导说重构系统,不出意外这是第4次重构系统了,当然去年就说了,今年年底才紧锣密鼓的执行。

而我现在所在的公司,经常调整计算公式,我的后端开发们天天写死计算公式在代码里面,虽然我只负责前端开发,依然在想提高前端的开发速度,代码至简,简单的代码实现复杂的功能。

当然这篇文章提出的重点就是围绕上面提出写死计算公式业务展开讨论与提出的计算公式模板实际方案是否可行。

我从后端提取一段平时写的冰山一角代码,转换为下面的一条公式:

50 * 0.5 + 25 + 150 * 2 + 100 * 0.5

// 模拟数据库返回
@Data
class KfcVMe50 {
    private BigDecimal money1; // 50
    private BigDecimal money2; // 25
    private BigDecimal money3; // 150
    private BigDecimal money4;// 100
    private BigDecimal ratio; //0.5
    private BigDecimal fold; //0.5
    private BigDecimal sum;
    public void getKfc(){
       this.setMoney1(new BigDecimal("50"));
       this.setMoney2(new BigDecimal("25"));
       this.setMoney3(new BigDecimal("150"));
       this.setMoney4(new BigDecimal("100"));
       this.setRatio(new BigDecimal("0.5"));
       this.setFold(new BigDecimal("2"));
    }
}

 

// 模拟计算逻辑
@Test
void sum (){
    var money = new KfcVMe50();
    money.getKfc();
    money.setSum(
          money.getMoney1()
                .multiply(money.getRatio())
                .add(money.getMoney2())
                .add(money.getMoney3())
                .multiply(money.getFold())
                .add(money.getMoney4())
                .multiply(money.getRatio())
    );

    System.out.println(money);
    System.out.println(execute("50*0.5+25+150*2+100*0.5"));
    System.out.println(
          BigDecimal.valueOf(50)
                .multiply(BigDecimal.valueOf(0.5)) // 50 * 0.5 = 25
                .add(BigDecimal.valueOf(25)) // 25 + 25 = 50
                .add(BigDecimal.valueOf(150)) //50 + 150  = 200
                .multiply(BigDecimal.valueOf(2)) //200 * 2 = 400
                .add(BigDecimal.valueOf(100)) // 400 + 100 = 500
                .multiply(BigDecimal.valueOf(0.5)) //500  * 0.5
    );

}

运行查看结果

假如某一天修改公式和添加一个字段,只能继续增加或修改代码了

接下来根据我提出的计算公式模板验证这个问题是否可行,根据上面的代码我们可以知道转换后的公式,先定义一个字符串公式

    //50*0.5+25+150*2+100*0.5 转换为字符串模板
	String nlms = "( ( ( ( money1 * ratio ) + money2 ) + money3 ) * fold + money4 ) * ratio ";
	
    @Test
	void templateSum() {
		var kfcVMe50 =  new KfcVMe50();
		kfcVMe50.getKfc();
		var map = (Map<String, Object>) JSON.toJSON(kfcVMe50);
		System.out.println("原来的计算模板:" + nlms);
		for (String key : map.keySet()) if (null != map.get(key)) nlms = nlms.replace(key.toString(), map.get(key).toString() ).toString();
		System.out.println("公式替换后:"+nlms);
		System.out.println("获取到公式计算结果: " + execute(nlms));
		kfcVMe50.setSum(execute(nlms));
		System.out.println("map=======>" + map);
		System.out.println(JSON.toJSONString(kfcVMe50));
	}
	BigDecimal execute( String resultNlms ){
		JEP jep = new JEP();
		jep.parseExpression(resultNlms);  // 解析公式
		BigDecimal result = BigDecimal.valueOf(jep.getValue());  // 获取结果
		return result;
	}

其实并不复杂,核心就是在这里,先把实体类转换为map,在遍历map替换公式里面的字符串,把替换好的字符串公式,使用 JEP 库执行计算公式,至此,以后的修改公式操作,我们只需要简单的维护计算公式模板,而不是代码本身,达到可扩展和维护简单的效果,甚至计算公式可交由业务人员维护

这不一定是最优的写法,但是确是一种灵活解决写死代码的方法,但是可以根据当前代码设计思想(灵魂)深入写出更好更灵活的bug

参考pom

		<dependency>
			<groupId>jep</groupId>
			<artifactId>jep</artifactId>
			<version>2.24</version>
		</dependency>
		<dependency>
			<groupId>com.alibaba.fastjson2</groupId>
			<artifactId>fastjson2</artifactId>
			<version>2.0.20</version>
		</dependency>

完整的参考代码:

 


	@Data
	class KfcVMe50 {
		private BigDecimal money1; // 50
		private BigDecimal money2; // 25
		private BigDecimal money3; // 150
		private BigDecimal money4;// 100
		private BigDecimal ratio; //0.5
		private BigDecimal fold; //0.5
		private BigDecimal sum;
		public void getKfc(){
			this.setMoney1(new BigDecimal("50"));
			this.setMoney2(new BigDecimal("25"));
			this.setMoney3(new BigDecimal("150"));
			this.setMoney4(new BigDecimal("100"));
			this.setRatio(new BigDecimal("0.5"));
			this.setFold(new BigDecimal("2"));
		}
	}
	@Test
	void sum (){
		var money = new KfcVMe50();
		money.getKfc();
		money.setSum(
				money.getMoney1()
						.multiply(money.getRatio())
						.add(money.getMoney2())
						.add(money.getMoney3())
						.multiply(money.getFold())
						.add(money.getMoney4())
						.multiply(money.getRatio())
		);

		System.out.println(money);
		System.out.println(execute("50*0.5+25+150*2+100*0.5"));
		System.out.println(
				BigDecimal.valueOf(50)
						.multiply(BigDecimal.valueOf(0.5)) // 50 * 0.5 = 25
						.add(BigDecimal.valueOf(25)) // 25 + 25 = 50
						.add(BigDecimal.valueOf(150)) //50 + 150  = 200
						.multiply(BigDecimal.valueOf(2)) //200 * 2 = 400
						.add(BigDecimal.valueOf(100)) // 400 + 100 = 500
						.multiply(BigDecimal.valueOf(0.5)) //500  * 0.5
		);

	}
	//50*0.5+25+150*2+100*0.5
	String nlms = "( ( ( ( money1 * ratio ) + money2 ) + money3 ) * fold + money4 ) * ratio ";
	@Test
	void templateSum() {
		var kfcVMe50 =  new KfcVMe50();
		kfcVMe50.getKfc();
		var map = (Map<String, Object>) JSON.toJSON(kfcVMe50);
		System.out.println("原来的计算模板:" + nlms);
		for (String key : map.keySet()) if (null != map.get(key)) nlms = nlms.replace(key.toString(), map.get(key).toString() ).toString();
		System.out.println("公式替换后:"+nlms);
		System.out.println("获取到公式计算结果: " + execute(nlms));
		kfcVMe50.setSum(execute(nlms));
		System.out.println("map=======>" + map);
		System.out.println(JSON.toJSONString(kfcVMe50));
	}
	BigDecimal execute( String resultNlms ){
		JEP jep = new JEP();
		jep.parseExpression(resultNlms);  // 解析公式
		BigDecimal result = BigDecimal.valueOf(jep.getValue());  // 获取结果
		return result;
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值