Java Bipredicate的类型安全容器
我有一个设计问题,我不知道如何解决。 我创建了一个计算解析表达式的Java Bipredicate的类型安全容器,java,oop,generics,design-patterns,wildcard,Java,Oop,Generics,Design Patterns,Wildcard,我有一个设计问题,我不知道如何解决。 我创建了一个计算解析表达式的计算器类。表达式的形状为amount>50。运算符用于理解必须创建哪个谓词。然后,LHS被发送到另一个对象以获取其实际值。该值可以是字符串、整数、双精度等。 当我尝试创建相应的谓词并用适当的值初始化它时,问题就开始了。我得到警告,它是不安全的类型,使用原始类型等。我想解决这个问题,如果我可以和不抑制警告。我目前的想法是创建一个容器类,我将其命名为Value,这是通用的。但我一直坚持这一思路。我的代码: public class
计算器类。表达式的形状为amount>50
。运算符用于理解必须创建哪个谓词。然后,LHS被发送到另一个对象以获取其实际值。该值可以是字符串
、整数
、双精度
等。
当我尝试创建相应的谓词
并用适当的值初始化它时,问题就开始了。我得到警告,它是不安全的类型,使用原始类型等。我想解决这个问题,如果我可以和不抑制警告。我目前的想法是创建一个容器类,我将其命名为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;
};
}
}
公共类评估员{
静态PredicateFactory predFactory=新的PredicateFactory();
公共布尔求值(字符串[]表达式,数据){//目前实际上不起作用,只是测试
BiPredicate谓词=predFactory.createPred(表达式[1]);
test(data.getAttribute(表达式[0]),50);
}
}
公共类谓词属性{
公共双预测createPred(字符串运算符){
返回开关(操作员){
格“->(双预测)(i,j)->i>Double.parseDouble(j);
案例“来自域”->(双预测)(i,j)->i.endsWith(“@”+j”);
默认->空;
};
}
公共阶级价值{
私人旅行社;
值(T val){
this.val=val;
}
公共T getVal(){
返回此.val;
}
}
公共类数据{
私有int-id;
私人国际总价格;
私有字符串日期;
私人字符串电子邮件;
....
数据(整数id、整数价格、字符串日期、字符串电子邮件等){
this.id=id;
此项。总价=价格;
this.date=日期;
this.email=电子邮件;
.....
}
公共值getAttribute(字符串属性){
返回开关(属性){
案例“价值”->新价值(双倍于此总价);
案例“email”->新值(this.email);
默认->空;
};
}
}
感谢您的指点您可以:
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-createPred(字符串运算符){
返回开关(操作员){
大小写“”->(i,j)->(Double)i>Double.parseDouble((String)j);
大小写“来自域”->(i,j)->((String)i).endsWith(“@”+j);
默认->空;
};
}
或者使用包装器/持有者类(但这需要为每个值创建一个额外的实例,这意味着它的效率不高。因此我更喜欢上面提到的实现):
public-BiPredicate-createPred(字符串运算符){
返回开关(操作员){
大小写“”->(i,j)->i.number>Double.parseDouble(j.string);
大小写“from domain”->(i,j)->i.string.endsWith(“@”+j.string”);
默认->空;
};
}
公共静态类持有者{
公众双倍号码;
公共字符串;
公众持有人(双倍号码){
这个数字=数字;
}
公众持有人(字符串){
this.string=string;
}
}
如果您确定只会输入正确的类型(作为调用谓词时的参数),那么抑制警告应该是完全正确的,您不必担心。否则,您可以使用“Object”作为谓词的类型,然后使用“instanceof”检查labda(谓词)中对象的类型。这应该会使警告消失,但如果永远不会有不正确的输入,这将是不必要的。感谢@intovid的回复,我肯定会输入正确的类型。我完全可以控制这一点。但是,抑制警告不是一个坏的编码习惯吗?我想避免长时间切换:instanceofs、feels over的情况y复杂且不可缩放这就是为什么我建议使用对象作为谓词的类型,然后在labda中将对象强制转换为您需要的任何类型。如果未使用instanceof,则当输入错误的参数时,它将抛出错误(这很好,因为您可以直接知道代码是否会产生输入错误数据类型的状态)(如果不使用instanceof,则可能会出现另一个警告,但这次是在labda内部,而不是在调用它的位置)。我真的想不出另一个不需要包装器类的解决方案。oop
标记似乎放错了地方。在oop中,数据和逻辑是结合在一起的。这里数据和逻辑是分开的。也许目标是函数式编程?@intovid我会尝试使用Object,但我很想听听你对包装器的意见-我不是非常有经验,并试图使这个设计尽可能最好,所以如果它是一个好的设计,我愿意实现我必须实现的。@jaco0646,你可能是对的-虽然我只是在这个特定的情况下分离数据和逻辑。你认为数据
类处理布尔求值逻辑更有意义吗?
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;
}
}