Java如何优雅的通过表格中的规则计算结果

各位大神,下午好,请看问题描述:

Java程序需要根据下面表格中的规则计算得到物品编号:

红色 黑色
高<10 20<高<50 ... ... 高>1000
宽<20 FA VF ... ... QT
20<=宽<30 TA MF ... ... ZA
30<=宽<80 YN VF ... ... OP
宽>=80 UI SR ... ... OH

注:表格中的...表示省略的更多规则

现在的写法:

Box box = boxService.getBoxById(10);
String boxCode = "";

if(box.getWidth()<20){
    if(box.getColor()=="红色"){
        if(box.getHeight()<10){
            boxCode = "FA";
        }else if(box.getHieght() > 20 && box.getHieght() <50){
            boxCode = "VF";
        }
        //省略...
    }else if(box.getColor()=="黑色"){
        //省略...
    }
}else if(box.getWidth()>=20){
    //省略...
}

上述写法需要大量的 if else ,而且如果条件过多,需要写很多代码, 请问有什么方法、工具可以优雅的处理这种问题吗?谢谢。

阅读 3.4k
6 个回答

存在这样的二维表格,虽然不是很规整,但是说明稍加处理是可以查表的。

下面的代表中定义了两个辅助类:ColumnRow。核心代码在 getCode() 中。整个逻辑可以封装在一个工具类中,getCode 中取 row 和 column 的逻辑可以独立成函数,然后在 getCoe 中用 stream 和 optional 来组合逻辑。

package playground.sf.q1010000042100219;

import java.util.List;

public class Solution {
    private static List<Row> rows = initRows();
    private static List<Column> columns = initColumns();

    static String getCode(int width, int height, String color) {
        var row = rows.stream()
            .filter(it -> it.inRange(width))
            .findFirst()
            .orElse(null);
        if (row == null) { return null; }
        var column = columns.stream()
            .filter(it -> it.getColor().equals(color) && it.inRange(height))
            .findFirst()
            .orElse(null);
        if (column == null) { return null; }

        return row.getCodes()[column.getIndex()];
    }

    public static void main(String[] args) {
        System.out.println("Code: " + getCode(5, 5, "红色"));
        System.out.println("Code: " + getCode(15, 25, "红色"));
        System.out.println("Code: " + getCode(5, 1024, "黑色"));
        System.out.println("Code: " + getCode(115, 115, "红色"));
    }

    private static List<Row> initRows() {
        return List.of(
            new Row(-1, 20, "FA", "VF", "QT"),
            new Row(20, 30, "TA,MF,ZA".split(",")),
            new Row(30, 80, "YN,VF,OP".split(",")),
            new Row(80, -1, "UI,SR,OH".split(","))
        );
    }

    private static List<Column> initColumns() {
        int i = 0;
        return List.of(
            new Column(i++, "红色", -1, 10),
            new Column(i++, "红色", 20, 50),
            new Column(i++, "黑色", 1000, -1)
        );
    }

    public static class Row {
        private final int[] range;
        private final String[] codes;

        public Row(int min, int max, String... codes) {
            range = new int[] { min, max };
            this.codes = codes;
        }

        public int[] getRange() {
            return range;
        }

        public String[] getCodes() {
            return codes;
        }

        public boolean inRange(int value) {
            return (range[0] < 0 || range[0] <= value)
                && (range[1] < 0 || range[1] > value);
        }
    }

    public static class Column {
        private final int index;
        private final String color;
        private final int[] range;

        public Column(int index, String color, int min, int max) {
            this.index = index;
            this.color = color;
            this.range = new int[] { min, max };
        }

        public boolean inRange(int value) {
            return (range[0] < 0 || range[0] <= value)
                && (range[1] < 0 || range[1] > value);
        }

        public int getIndex() {
            return index;
        }

        public String getColor() {
            return color;
        }

        public int[] getRange() {
            return range;
        }
    }
}
let goodsConfig = new Map([
    [(color='',width=0,height=0)=>(color==='红色'&&width<20&&height<10),['FA','TA']],
    [(color='',width=0,height=0)=>(color==='红色'&&width>=20&&height<10),['YN','UI']],
    [(color='',width=0,height=0)=>(color==='红色'&&width<20&&20<height<50),['VF','MF']],
    [(color='',width=0,height=0)=>(color==='红色'&&width>=20&&20<height<50),['UI','SR']],
                          ]);
let getCode=(color='',width=0,height=0)=>{
 let res=[];
 for(let [fun,val] of goodsConfig.entries()){
    if(fun(color,width,height)){
        res = val;
        break;
    }
 }
 return res;
}
getCode('红色',10,30);
(2) ['VF', 'MF']

用js 实现了,参考@边城
https://segmentfault.com/a/11...

生成map,遍历表格,宽<20,红色,高<10 这三个数据md5一下,当做key,FA作为value

看错题目了,觉得把规则提出来比较好

    public static void main(String[] args) throws ScriptException {
        String code = "if(color==='红色'&&width<20&&height<10) return 'NA'; else return 'FA';";
        HashMap map = new HashMap();
        map.put("color","红色");
        map.put("width",10);
        map.put("height",3);
        System.out.println(eval(code,map));
    }
    static String eval(String code, HashMap<String,String> param_map) throws ScriptException {
        code = "function f () {" + code + "} f()"; // Or otherwise
        ScriptEngineManager factory = new ScriptEngineManager();
        ScriptEngine engine = factory.getEngineByName("JavaScript");
        param_map.entrySet().forEach(stringStringEntry -> {
            engine.put(stringStringEntry.getKey(),stringStringEntry.getValue());
        });
        String result =  (String)engine.eval(code);
        return result;
    }

策略模式应该能优雅的解决一下你的问题

规则引擎Drools

//规则一:所购图书总价在100元以下的没有优惠
rule "book_discount_1"
    when
        $order:Order(originalPrice < 100)
    then
        $order.setRealPrice($order.getOriginalPrice());
        print("所购图书总价在100元以下的没有优惠");
end

//规则二:所购图书总价在100到200元的优惠20元
rule "book_discount_2"
    when
        $order:Order(originalPrice < 200 && originalPrice >= 100)
    then
        $order.setRealPrice($order.getOriginalPrice() - 20);
        print("所购图书总价在100到200元的优惠20元");
end

//规则三:所购图书总价在200到300元的优惠50元
rule "book_discount_3"
    when
        $order:Order(originalPrice <= 300 && originalPrice >= 200)
    then
        $order.setRealPrice($order.getOriginalPrice() - 50);
        print("所购图书总价在200到300元的优惠50元");
end

//规则四:所购图书总价在300元以上的优惠100元
rule "book_discount_4"
    when
        $order:Order(originalPrice >= 300)
    then
        $order.setRealPrice($order.getOriginalPrice() - 100);
        print("所购图书总价在300元以上的优惠100元");
end

function void print(String message){
    System.out.printf("成功匹配到规则:%s",message);
}

有递进关系 宽 [10,20,30,..,100] 高 [10,20,30,..,100]
宽 for 宽; if i++ ; else break;
高 for 高; if j++ ; else break;
res[i][j]

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏