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

I am writing a class of financial calculations that will have several inputs of the setter function, some private intermediate values ​​and a number of getter functions as outputs.

  • Particular intermediate values ​​depend only on the input values.

  • Output values ​​(accessible by public getters) depend only on inputs and intermediate values.

Ultimately, you could draw all of this as a somewhat confusing acyclic oriented graph with a bunch of inputs on one side, ultimately flowing to a bunch of outputs on the right side.

What is the best way to implement this class. I have some special requirements:

  • If possible, lazy appreciation. When the input changes, we now know what weekends may be required.

  • The class should be easily reconstructed, so some declarative model could be described.

Ideally, I would like to say that C depends on A and B. If C were requested after A or B were changed, then he would know that C needs to be recalculated, otherwise C will never be needed for updating.

Do I have a Java template that can help me cleanly implement this calculator?

+8
java design design-patterns
source share
4 answers

You can build a solution by creating a future meaning that will be retellable.

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

He is completely lazy and defines addictions.

+2
source share

You can use such a template.

 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); } } 
+2
source share

It looks like you have some kind of real-time stream processing problem.

Take a look at twitter storm . Even if you decide not to use it, you can lend some concepts explained on the page.

+2
source share

Personally, I agree with Peter, but for the sake of argument, I have two more answers. I would recommend looking at the rules engine (e.g. Drools) to implement such a flexible business logic. They are designed so that update rules between variables are easily set and changed at will. They should also be quite effective.

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

 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 will look like this:

 <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 an additional loan, you can implement a bean post-processor for automatic calculation and installation of dependencies 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(); } } 
+1
source share

All Articles