gpt4 book ai didi

java - 将类型推广到 Java 中的类型系统

转载 作者:行者123 更新时间:2023-11-30 01:42:55 26 4
gpt4 key购买 nike

我有一些代码,其中存在诸如事件之类的对象,它具有属性的集合,其中任何人都可以通过调用事件来获取值方法:Double getAttributeValue(整数索引)。到目前为止,方法签名中的 AtributeValue 始终为 Double。现在它可以是其他新类,我需要概括代码,因此在 Double 上应用的任何运算符都应该在我的新类系统上工作。此外,这些类不仅应该像旧代码中那样在同一个类之间进行操作,而且还应该在彼此之间与相同的运算符进行交互。对于 exmaple,旧代码的操作如下:

private Double calculateDelta(Event event) {
Double firstValue = (Double)event.getAttributeValue(StockEventTypesManager.firstStockMeasurementIndex);
Double secondValue = (Double)event.getAttributeValue(StockEventTypesManager.firstStockMeasurementIndex + 1);
return Math.abs(firstValue - secondValue);
}

新代码应该执行如下操作:

private AttributeValue calculateDelta(Event event) {
AttributeValue firstValue = (AttributeValue )event.getAttributeValue(StockEventTypesManager.firstStockMeasurementIndex);
AttributeValue secondValue = (AttributeValue )event.getAttributeValue(StockEventTypesManager.firstStockMeasurementIndex + 1);
return Math.abs(AttrValueFunctional.minus(firstValue,secondValue));
}

或者类似的东西(这些只是建议,因为我不知道如何设计它):

private AttributeValue calculateDelta(Event event) {
AttributeValue firstValue = (AttributeValue )event.getAttributeValue(StockEventTypesManager.firstStockMeasurementIndex);
AttributeValue secondValue = (AttributeValue )event.getAttributeValue(StockEventTypesManager.firstStockMeasurementIndex + 1);
return (firstValue.minus(secondValue)).abs();
}

其中此代码可以对应于这些语句对中的每一对:

boolean isDoubleWrapper = firstValue isinstanceof DoubleWrapper; //true
boolean isDoubleList = secondValue isinstanceof DoublePairsList; //true

boolean isDoubleList = firstValue isinstanceof DoublePairsList; //true
boolean isDoubleWrapper = secondValue isinstanceof DoubleWrapper; //true

boolean isDoubleWrapper = firstValue isinstanceof DoubleWrapper; //true
boolean isDoubleWrapper = secondValue isinstanceof DoubleWrapper; //true

boolean isDoublePairsList = firstValue isinstanceof DoublePairsList; //true
boolean isDoublePairsList = secondValue isinstanceof DoublePairsList; //true

也可能是:

boolean isStrangeObject = firstValue isinstanceof StrangeObject; //true
boolean isDoubleList = secondValue isinstanceof DoublePairsList; //true

boolean isDoubleList = firstValue isinstanceof DoublePairsList; //true
boolean isStrangeObject = secondValue isinstanceof StrangeObject; //true

boolean isStrangeObject = firstValue isinstanceof StrangeObject; //true
boolean isStrangeObject = secondValue isinstanceof StrangeObject; //true

boolean isDoublePairsList = firstValue isinstanceof DoublePairsList; //true
boolean isDoublePairsList = secondValue isinstanceof DoublePairsList; //true

我伟大的设计目标是让 future 的任何编码器都​​可以轻松添加一些可以“隐藏”在 AttributeValue 中的新类,添加所需的操作功能(加、减、abs),因此新类应该具有良好的可扩展性。

我尝试了一些实现,其中之一通常可以工作(如下所示),但我不认为它遵循最好的java设计模式,或者它具有良好的可扩展性并且易于添加我提到的新类。

public class Main {
public interface Operand {}

public interface Combiner<T> {
T subtract(T a, T b);
}

public static abstract class MyFunctional {

public static<T extends Operand> T
compute(Operand a, Operand b, Subtracter combiner) {
return (T) combiner.subtract(a, b);
}

private static A subtractAA(A a, A b){
return new A(a.getFirst() - b.getFirst(), a.getSecond()-b.getSecond());
}

private static A subtractAB(A a, B b){
return new A(a.getFirst() - b.getFirst(), a.getSecond()-b.getSecond()-b.getThird());
}

static class
Subtracter implements Combiner<Operand> {
@Override
public Operand subtract(Operand x, Operand y) {

if(x instanceof A && y instanceof A){
return subtractAA((A)x,(A)y);
}
if(x instanceof A && y instanceof B){
return subtractAB((A)x,(B)y);
}
return null;
}
}

}


public static class A implements Operand{
private int a;
private int b;

public A(int a, int b){
this.a=a;
this.b=b;
}
public int getFirst(){
return a;
}

public int getSecond() {
return b;
}

@Override
public String toString() {
return "("+a+" "+b+")";
}
}

public static class B implements Operand {
private int a;
private int b;
private int c;

public B(int a, int b, int c){
this.a=a;
this.b=b;
this.c = c;
}
public int getFirst(){
return a;
}

public int getSecond() {
return b;
}

public int getThird() {
return b;
}

@Override
public String toString() {
return "("+a+" "+b+" "+c+")";
}
}

public static void main(String[] args) {

Operand e = new A(1, 2);
Operand f = new A(3,4);
Operand g = new B(3,4,5);
System.out.println("Hello World");

System.out.println((Object)MyFunctional.compute(e,f, new MyFunctional.Subtracter()));

Operand o = MyFunctional.compute(f,g, new MyFunctional.Subtracter());

System.out.println("Bye");
}
}

这是我尝试做的一个小例子。任何人都可以尝试更改我的代码或为那些简单的 A、B 类建议他自己的代码,这将很容易适应新类(例如,如果想要添加一些带有 4 个字段的简单类 C 以及加法和减法运算) C 与其自身之间以及 A 与 C 之间以及 B 与 C 之间),这将按照我在此处和乞讨中所描述的方式工作(实际上几乎相同)。

在回答几个问题后进行编辑:新类型的真实域:所以在老问题中,Double 类型意味着一个确定性值(这意味着这个值在现实世界中以 1.0 的概率已知)。现在我需要将其替换为图中的类型系统。 enter image description here现在介绍操作和操作数功能:同一分支中的每两个对象都应与其自身作为其第一祖先进行操作。不同分支的两个对象应该像它们的第一个祖先一样进行相同的操作。

所以最终我想根据新的假设重构代码:

event.getAttributeValue(index);

可以返回所描述的可能层次结构中的任何类。当然,现在我需要编写一段代码,仅实现两个最左边的高对象以及它们之间的所有操作,如减法、加法等。我的目标是为这个问题设计正确的接口(interface)和类框架。

根据上次更新的答案进行的另一项澄清:

我想做的是某种包装器和功能即策略设计模式,如下面链接中的两个代码所示:

第一个(不是模板示例,我需要根据上次更新的答案进行概括): first

第二个(类似这样,但根据建议的解决方案使用 Class、Class 以及 BiFunction 和 BinaryOperator): second

最佳答案

已经有一个类:BinaryOperator .

忘记像 AttributeValue 这样的包装类。只需让 Event 继续像以前一样保存简单值(包括 Double),并将组合操作作为 BinaryOperator 传入即可。

由于类型删除,转换为泛型类型(如 T)是不安全的操作,因此您还需要传递类型:

private <V> V calculateDelta(Event event,
Class<V> valueType,
BinaryOperator<V> operation) {

V firstValue = valueType.cast(
event.getAttributeValue(
StockEventTypesManager.firstStockMeasurementIndex));

V secondValue = valueType.cast(
event.getAttributeValue(
StockEventTypesManager.firstStockMeasurementIndex + 1));

return operation.apply(firstValue, secondValue);
}

对该方法的调用如下所示:

Double delta =
calculateDelta(eventToProcess, Double.class, (a, b) -> a - b);

更新:

您在评论中指出操作数并不总是同一类型。在这种情况下,您可以使用 BiFunction而不是 BinaryOperator:

private <V, U, R> R calculateResult(Event event,
Class<V> firstValueType,
Class<U> secondValueType,
BiFunction<V, U, R> operation) {

V firstValue = firstValueType.cast(
event.getAttributeValue(
StockEventTypesManager.firstStockMeasurementIndex));

U secondValue = secondValueType.cast(
event.getAttributeValue(
StockEventTypesManager.firstStockMeasurementIndex + 1));

return operation.apply(firstValue, secondValue);
}

但是,事实证明您可以同时做到这两点!对于您希望两个值和结果具有相同类型的情况,您可以使用上述方法,也可以使用第一个版本以方便使用:

private <V> V calculateResult(Event event,
Class<V> valueType,
BinaryOperator<V> operation) {

return calculateResult(event, valueType, valueType, operation);
}

说明:

BiFunction 和 BinaryOperator 都是函数式接口(interface),即只有一个抽象方法的接口(interface)。 (staticdefault 方法不是抽象方法。)

这意味着可以使用 lambda 来表示它。 (a, b) -> a - b) 与此相同:

new BinaryOperator<Double>() {
@Override
public Double apply(Double a, Double b) {
return a - b;
}
}

所以,lambda 实际上是 BiFunction 或 BinaryOperator。

它不一定是 lambda。它也可以是方法引用:

private Double subtract(Double a, Double b) {
return a - b;
}

// ...

Double delta =
calculateResult(eventToProcess, Double.class, this::subtract);

当然,您可以使这样的方法变得更复杂:

private Double probabilityFor(DiscreteDistribution d, Integer x) {
Map<Integer, Double> probabilities = d.getProbabilities();
return probabilities.getOrDefault(x, 0);
}

// ...

Double probability =
calculateResult(eventToProcess,
DiscreteDistribution.class,
Integer.class,
this::probabilityFor);

您还可以定义对复杂对象本身的操作:

public class DiscreteDistribution {
private final Map<Integer, Double> probabilities = new HashMap<>();

// ...

public Double probabilityOf(int x) {
return probabilities.getOrDefault(x, 0);
}
}

public class ValueCalculator {

// ...

Double probability =
calculateResult(eventToProcess,
DiscreteDistribution.class,
Integer.class,
DiscreteDistribution::probabilityOf);

}

关于java - 将类型推广到 Java 中的类型系统,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59313881/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com