有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

oop在Java中将一个类型泛化为一个类型系统

我有一些代码,其中有一个对象,比如事件,它有一组属性,任何人都可以通过调用事件方法双getAttributeValue(整数索引)。 到目前为止,该方法的特征码中的阿替布特值始终是双倍的。现在它可以是其他新类,我需要对代码进行泛化,所以任何应用于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

我伟大的设计目标是使未来的任何程序员都能轻松地添加一些新类,这些类可以“隐藏”在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类建议自己的代码,这些类将很容易适应新的类(例如,如果想要添加一些简单的C类,包含4个字段,以及C和自身之间以及A和C、B和C之间的加法和减法运算),正如我在这里和《乞讨》中所描述的那样(实际上基本相同)

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

因此,最终我想将代码重构为新的假设:

event.getAttributeValue(index);

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

由于上一次更新的答案,另一个澄清:

我想做的是某种包装和功能性策略设计模式,就像下面链接中的两个代码:

首先(不是模板化的示例,我需要根据最后更新的答案进行概括): first

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


共 (1) 个答案

  1. # 1 楼答案

    已经有一个类用于此:BinaryOperator

    忘记像AttributeValue这样的包装类吧。只需让事件继续像以前一样保存简单的值,包括double,并将合并操作作为二进制运算符传递

    由于类型擦除,强制转换为泛型类型(如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而不是二进制运算符:

    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都是函数接口,也就是说,只有一个抽象方法的接口。(staticdefault方法不是抽象方法。)

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

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

    所以,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);
    
    }