Best design pattern to support static functions of generic classes that implements interface

Viewed 326

I have an interface Operations:

public interface Operations{

    Operations add(Operations op);

    Operations subtract(Operations op);
}

This interface should allow the user to choose how to do simple calculations. For example if the user just wants to use the data type Integer and its basic operations he can use the class MyInteger:

// simple implementation without type check etc..
public final class MyInteger implements Operations{
    private final int delegate;

    public MyInteger(int i){
        delegate = i;
    }

    @Override
    Operations add(Operations other){
        return new MyInteger(delegate + ((MyInteger) other).delegate);
    }
    @Override
    Operations subtract(Operations other){
        return new MyInteger(delegate - ((MyInteger) other).delegate);
    }
    (...)
}

In other classes there will take place calculations based on the functions of the interface Operations. But sometimes i need a static context like valueOf(val) functions that returns an implementation of the corresponding class for a given String, double, int and so on , like in this example:

public class Calculation<D extends Operations> {

    private final D value1, value2;
    private final D value3 = D.valueOf(4);  // cannot implement this in interface 

    public Calculation(D value1, D value2){
        this.value1 =value1;
        this.value2 = value2;
    }

    public D sumPlusValue3(){
        return value1.plus(value2).plus(value3);
    }
}

So

Calculation<MyInteger> calc = new Calculation<MyInteger>(new MyInteger(1), new MyInteger(2));
Operations result = calc.sumPlusValue3();

In general i think i have to use a design pattern like Builder or a Factory to allow the user to specify which implementation he wants, like

Operations integerImpl = OperationsBuilder.create("Integer");

But also after studying those patterns, i could not find a clean way to get an implementation of the generic class D for value3 in the Calculation class.

EDIT 1:

I edited the question and marked the answer from @Stefan Haustein because it was the best solution for my problem. But the answer from @davidxxx is also a good answer regarding my initial question - how to represent only a valueOf(int val) function.

2 Answers

1) Initial problem : factory invocation

Here :

private final D value3 = D.valueOf(4);  // cannot implement this in interface 

You want value value3 with a generic that is not a factory.
Defining valueOf() in the interface (so as an instance method) is not either a solution.

As alternative, you could introduce a factory parameter in the Calculation constructor to have a way to value value3.

So replace :

private final D value3 = D.valueOf(4);

public Calculation(D value1, D value2){
    this.value1 =value1;
    this.value2 = value2;
}

by :

private final D value3; 

public Calculation(D value1, D value2, FactoryD factoryD){
    this.value1 =value1;
    this.value2 = value2;
    this.value3 = factoryD.create(4);
}

or better use the Function functional interface for the factory :

private final D value3; 

public Calculation(D value1, D value2, IntFunction<D> factoryD){
    this.value1 =value1;
    this.value2 = value2;
    this.value3 = factoryD.apply(4);
}

You could so use it like that :

Calculation<MyInteger> calc = new Calculation<>(new MyInteger(1), new MyInteger(2), MyInteger::new );
Operations result = calc.sumPlusValue3();

But Operations misses something.

2) No way to represent Operations value.

Actually, Operations defines operations methods but no way to display the object value :

public interface Operations{

    Operations add(Operations op);

    Operations subtract(Operations op);
}

You should rather define with a way to get the value and make the interface generic to handle any type of value :

public interface Operations<T> {

    Operations<T> add(Operations<T> op);

    Operations<T> subtract(Operations<T> op);

    T getValue();

}

MyInteger can so be defined as :

public final class MyInteger implements Operations<Integer> {

    private final int delegate;

    public MyInteger(int i) {
      delegate = i;
    }

    @Override
    public Operations<Integer> add(Operations<Integer> other) {
      return new MyInteger(delegate + other.getValue());
    }

    @Override
    public Operations<Integer> subtract(Operations<Integer> other) {
      return new MyInteger(delegate - other.getValue());
    }

    @Override
    public Integer getValue() {
      return delegate;
    }
}

And Calculation could be so defined with two generics : one for the Operations and another for Operations return type :

public class Calculation<C, D extends Operations<C>> {

    private final D value1, value2;
    private final D value3; 

    public Calculation(D value1, D value2, IntFunction<D> factoryD){
        this.value1 =value1;
        this.value2 = value2;
        this.value3 = factoryD.apply(4);
    }

    public Operations<C> sumPlusValue3(){
        return value1.add(value2).add(value3);
    }        
}

You can so use this code in this way :

Calculation<Integer, MyInteger> calc = new Calculation<>(new MyInteger(1), new MyInteger(2), MyInteger::new );
Operations<Integer> result = calc.sumPlusValue3();
System.out.println(result.getValue());

Output :

7

If in Calculation you always have an instance of D nearby anyway, you could just make valueOf a non-static member of Operations although technically you don't need the corresponding value.

If using a "dummy" instance for valueOf is not an option, you could require Class<D> as a constructor parameter for Calculations. That would allow you to call newInstance(), perhaps providing a neutral element -- but you would still require an operation such as addInt to get to a concrete value. These ideas could be combined to just avoid the need of an explicit dummy value.

Another option would be to make valueOf abstract in Calculation, avoiding the dependency on a dummy instance, moving the burden to the Calculation instance creation:

Calculation<MyInteger> calc = new Calculation<MyInteger>(
    new MyInteger(1), new MyInteger(2)) {
      public MyInteger valueOf(int i) {
        return new MyInteger(i);
      }
    });

Operations result = calc.sumPlusValue3();

In general, this seems to be about the right balance between "purity" and "extra layers / complexity". I would lean towards being more pragmatic and avoiding overhead here -- at the expense of purity.

P.S. Another option might be to have an explicit factory interface but to store it as a field of the Operations class as a convention:

public final class MyInteger implements Operations{
  private final int delegate;

  public static final OperationsFactory<MyInteger> FACTORY = 
    new OperationsFactory<>() {
      @Override
      MyInteger valueOf(int i) {
        return new MyInteger(i);
      }
    };

  public MyInteger(int i){
      delegate = i;
  }

  @Override
  Operations add(Operations other){
      return new MyInteger(delegate + ((MyInteger) other).delegate);
  }
  @Override
  Operations subtract(Operations other){
    return new MyInteger(delegate - ((MyInteger) other).delegate);
  }
  (...)
}

This would at least keep the implementation side of everything together in one file...

Related