jeudi 12 décembre 2019

Generelize a type to a system of types in Java

I have some code where there is such object as Event, it has a collection of Attributes, which has values which anyone can get by calling the Event method: Double getAttributeValue(Integer index). Until now AtributeValue as in the method's signature was always Double. Now it can be other new Classes and I need to generalize the code so everywhere where any operators applied on Double should work on my new system of classes. Moreover the classes should operate not only as in the old code, one to same class, but also interact with same operators between one to another. for exmaple, the old code operated like this:

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);
    }  

The new code should operate something like this:

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));
    }

or something like this (those just suggestions, because I don't know how to design it):

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();
    }

where this code can be corresponding to each one of those pairs of statements:

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

it also could be:

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

My great design goal is to make it possible to any coder in the future easily add some new classes which could "hide" in AttributeValue, add the needed operational functionality (add, subtract, abs), so there should be good scalability to new classes.

I tried some implementations, one of them generally works (the one showed below), but I don't think it's following the best java design patterns or it has good scalability and easy to add new classes ass I mentioned.

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");
    }
}

That's a kind of a small example of what I tried to do. Can anyone try to change my code or suggest his own code for those simple A,B classes, which will be easy to adjust to new classes (for example if will want to add some simple class C with 4 fields and the addition and subtraction operations between C and itself and between A and C and B and C), which will work as I described here and in the begging (pretty much the same actually).

Aucun commentaire:

Enregistrer un commentaire