Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I implement a lazy-evaluated stateful class with internal dependencies in Java?

I'm writing a financial calculation class which will have a number of setter function inputs, some private intermediate values and a number of getter functions as outputs.

  • The private intermediate values are only dependant on the input values.

  • The output values (accessed by public getters) are only dependant on the inputs and the intermediate values.

Ultimately you could draw the whole thing as a somewhat tangled acyclic directed graph whith a bunch of inputs on one side, eventually flowing to a bunch of outputs on the right hand side.

What's the best way to implement this class. I have some spesific requirements:

  • Where possible, lazy evaluate. When an input changes we have now way of knowing what outputs might be required.

  • The class has to be easy to re-design, so some kind of declarative model would epreferred.

Ideally I'd like to be able to say that C depends on A and B. If C were requested after either A or B had changed then it would know tht C needed to be re-calculated, otherwise C would never need to be refreshed.

IIs there a Java pattern that might help me cleanly implement this kind of calculator?

like image 276
Salim Fadhley Avatar asked Feb 10 '12 12:02

Salim Fadhley


4 Answers

You can build a solution by creating a future value that is recalculable.

public class Computation<T> {
   private T value;
   private Set<Computation<?>> usedBy;

   public T getValue(Computation<?> getter) {
     if (usedBy == null) {
       // value was not computed
       value = compute();
       usedBy = new HashSet();
     }
     if (getter != null) {
       // add a dependency
       usedBy.add(getter);
     }
     return value;
   }

   protected T compute() {
     // override when needed a lazily-computed value
     return null;
   }

   public void setValue(T value) {
     // invalidate this value
     invalidate();
     // set the new value
     this.value = value;
     usedBy = new HashSet();
   }

   public void invalidate() {
     if (usedBy != null) {
       for (Computation<?> c : usedBy) {
         c.invalidate();
       }
       usedBy = null;
     }
     value = null;
   }
}

public class Business {
  private Computation<Integer> a = new Computation<Integer>();
  private Computation<Integer> b = new Computation<Integer>();
  private Computation<Integer> c = new Computation<Integer>() {
    public Integer compute() {
      return a.getValue(this) + b.getValue(this);
    }
  };

  public void setA(int v) {
    a.setValue(v);
  }
  public void setB(int v) {
    b.setValue(v);
  }
  public int getC() {
    return c.getValue(null);
  }
}

It is completely lazy and figures out the dependencies.

like image 162
Kru Avatar answered Nov 20 '22 13:11

Kru


You can use a pattern like this.

double[] inputs = { ... }
double[] previousInputs = { Double.NaN, etc }; // NaN is never equal.
double[] outputs = 

public void update() {
   if (!Arrays.equals(inputs, previousInputs)) {
       recalculate(inputs, outputs);
       copyTo(inputs, previousInputs);
   }
}
like image 27
Peter Lawrey Avatar answered Nov 20 '22 13:11

Peter Lawrey


Seems like you have some sort of real-time stream processing problem.

Take a look at twitter storm. Even if you decide not to use it you can borrow some concepts explained at tutorial page.

like image 2
Mairbek Khadikov Avatar answered Nov 20 '22 12:11

Mairbek Khadikov


Personally I agree with Peter but for arguments sake I have two other answers. I would recommend looking at a rules engine (e.g. Drools) for implementing flexible business logic like this. They are designed so that the rules for updates between variables are easy to set and change at will. They should also be fairly performant.

Then, for the DYI-er, here is a Spring inspired version. The biggest drawback is that you get your dependencies as a list. You could easily use a HashMap but then you'd lose your syntax-safety.

public abstract class Variable<T> {

  private T currentValue;
  private List<Variable<?>> dependencies = new ArrayList<Variable<?>>();
  private List<Variable<?>> upstream = new ArrayList<Variable<?>>();

  public T get() {
    return currentValue;
  }

      public void set(T newValue) {
    currentValue = newValue;
    updateUpstream();
  }

  public abstract T recalculateValue(List<Variable<?>> dependencies);

  private void update() {
    set(recalculateValue());
  }

  private void updateUpstream() {
    for(Variable<?> variable : upstream) {
      variable.update();
    }
  }

  private void addUpstream(Variable<?> variable) {
    upstream.add(variable);
  }

  public void setDependencies(List<Variable<?>> dependencies) {
    this.dependencies = dependencies;
    for(Variable<?> variable) {
      variable.addUpstream(this);
    }
  }

}

The corresponding applicationContext.xml would look like:

<bean id="A" class="com.app.AVariable"/>
<bean id="B" class="com.app.BVariable"/>
<bean id="C" class="com.app.CVariable">
  <property name="dependencies">
    <list>
      <ref bean="A"/>
      <ref bean="B"/>
    </list>
  </property>
</bean>

For extra credit you could implement a bean post-processor to calculate and set the dependencies automatically based on annotations. For example:

public class CVariable extends Variable<Integer> {
  private AVariable a;
  private BVariable b;

  @Dependency
  public void setA(AVariable a) {
    this.a = a;
  }

  @Dependency
  public void setB(BVariable b) {
    this.b = b;
  }

  //If you were going this route you wouldn't need the list of dependencies
  public Integer recalculateValue() {
    return a.get() + b.get();
  }

}
like image 1
Pace Avatar answered Nov 20 '22 13:11

Pace