You could wrap the Map
and add your extra functionality to certain methods. Here I define a SummingMap
that could be a good start. I have left out many of the methods but they would just need to forward the call to the underlying map.
interface Summable {
public long getValue();
}
public static class Shop implements Summable {
private String name;
private long salesPerDay;
@Override
public long getValue() {
return salesPerDay;
}
}
public static class SummingMap<K, V extends Summable> implements Map<K, V> {
private final Map<K, V> map;
private long sum = 0;
public SummingMap(Map<K, V> map) {
this.map = map;
}
@Override
public V put(K key, V value) {
putting(key, value);
return map.put(key, value);
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
for ( Map.Entry<? extends K, ? extends V> e : m.entrySet() ) {
putting(e.getKey(), e.getValue());
}
map.putAll(m);
}
private void putting(K key, V value) {
if (map.containsKey(key)) {
sum -= map.get(key).getValue();
}
sum += value.getValue();
}
@Override
public V remove(Object key) {
Object o = map.get(key);
if (o != null && o instanceof Summable) {
sum -= ((Summable) o).getValue();
}
return map.remove(key);
}
// Other methods - just forward the call directly to the held map.
}
As @Christian correctly points out, this solution will not maintain the correct sums if you change the salesPerDay
value in the Store
objects without first removing them from the map.
You could enhance this solution by wrapping each object in a proxy but this again would not provide a guaranteed sum.
Making the the salesPerDay
field final may help too but nothing will achieve the guaranteed correctness of adding them all up on the fly at the time the total is needed.