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?
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.
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);
}
}
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.
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();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With