【问题标题】:Type safe container for BipredicateBipredicate 的类型安全容器
【发布时间】:2021-03-26 18:39:06
【问题描述】:

我有一个不知道如何解决的设计问题。 我创建了一个评估解析表达式的Evaluator 类。表达式的形状为amount > 50。运算符用于了解必须创建哪个谓词。然后,将 LHS 发送到不同的对象以获取其实际值。该值可以是StringIntegerDouble 等。 当我尝试创建正确的predicate 并使用正确的值对其进行初始化时,我的问题就开始了。我收到警告说它不是类型安全的,使用原始类型等。如果可以并且不抑制警告,我想解决这个问题。我目前的想法是创建一个容器类,我将其命名为Value,这是通用的。但我坚持继续这种思路。我的代码:


public class Evaluator {
    static PredicateFactory predFactory = new PredicateFactory();


    public boolean evaluate(String[] expression, Data data){ // currently doesn't actually work, just testing
        BiPredicate predicate = predFactory.createPred(expression[1]);
        predicate.test(data.getAttribute(expression[0]), 50);
    }
}

public class PredicateFactory {


    public BiPredicate<?,?> createPred(String operator) {
        return switch (operator) {
            case "<" -> (BiPredicate<Double, String>) (i, j) -> i <  Double.parseDouble(j);
            case ">" -> (BiPredicate<Double, String>) (i, j) -> i >  Double.parseDouble(j);
            case "from domain" -> (BiPredicate<String, String>) (i, j) -> i.endsWith("@" + j);
            default -> null;
        };
    }

public class Value<T>{
    private T val;

    Value(T val){
        this.val = val;
    }

    public T getVal(){
        return this.val;
    }
}


public class Data {
    private int id;
    private int total_price;
    private String date;
    private String email;
   ....

    Data(int id, int price, String date, String email, ){
        this.id = id;
        this.total_price = price;
        this.date = date;
        this.email = email;
.....
    }

    public Value<?> getAttribute(String attribute){ 
        return switch(attribute){
            case "value" -> new Value<>((double) this.total_price);
            case "email" -> new Value<>(this.email);
            default -> null;
        };

    }
}


感谢大家的指点

【问题讨论】:

  • 如果您确定只会输入正确的类型(作为调用谓词时的参数),那么抑制警告应该完全没问题,您不必担心。否则,您可以使用“Object”作为谓词的类型,然后使用“instanceof”检查 labda(谓词)中对象的类型。这应该会使警告消失,但如果永远不会有错误的输入,那就没有必要了。
  • 感谢@IntoVoid 的回复,我很肯定会输入正确的类型。我对此有完全的控制权。但是,抑制警告不是一个不好的编码习惯吗?我想避免长时间切换:instanceofs 的情况,感觉过于复杂和不可扩展
  • 这就是为什么我建议使用 Object 作为谓词的类型,然后将 labda 中的对象转换为您需要的任何内容。如果不使用instanceof,那么当输入不正确的参数时,它会抛出一个错误(这很好,因为您将直接知道您的代码是否可以产生输入错误数据类型的状态)(如果您不使用instanceof可能会有另一个警告,但这次是在 labda 内部,而不是你称之为的地方)。我真的想不出另一个不需要包装类的解决方案
  • oop 标签似乎放错了位置。在 oop 中,数据和逻辑是结合在一起的。这里数据和逻辑是分开的。也许目标是函数式编程?
  • @IntoVoid 然后我会尝试使用 Object,但很想听听您对包装器的意见 - 我不是很有经验,并试图使这个设计尽可能好,所以我如果它是好的设计,我愿意实施我必须做的事情。 @jaco0646,您可能是对的-尽管在这种特定情况下我只是将数据和逻辑分开。你会说Data 类处理布尔评估逻辑更有意义吗?

标签: java oop generics design-patterns wildcard


【解决方案1】:

你可以这样做:

public BiPredicate<Object, Object> createPred(String operator) {
    return switch (operator) {
        case "<" -> (i, j) -> (Double) i < Double.parseDouble((String) j);
        case ">" -> (i, j) -> (Double) i > Double.parseDouble((String) j);
        case "from domain" -> (i, j) -> ((String) i).endsWith("@" + j);
        default -> null;
    };
}

或使用包装器/持有者类(但这需要您为每个值创建一个额外的实例,这意味着它不会那么高效。所以我更喜欢上面提到的实现):

public BiPredicate<Holder, Holder> createPred(String operator) {
    return switch (operator) {
        case "<" -> (i, j) -> i.number < Double.parseDouble(j.string);
        case ">" -> (i, j) -> i.number > Double.parseDouble(j.string);
        case "from domain" -> (i, j) -> i.string.endsWith("@" + j.string);
        default -> null;
    };
}

public static class Holder {
    public double number;
    public String string;

    public Holder(double number) {
        this.number = number;
    }

    public Holder(String string) {
        this.string = string;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-21
    • 1970-01-01
    相关资源
    最近更新 更多