I have following code:
Container is an object that holds set of Parts. Some of parts are able to tell to container that they changed (ObservablePart notifies Container via someObservableMarketChanged method), and some just update their state (NonObservablePart). In case that ObservablePart changes, I need to do recalculation, and update all parts again (but this change is only applicable to NonObservableParts, ObservableParts have their values remain the same).
In this example I have 2 observable and 2 non-observable parts. Whenever any observable part changes, I have to take as input all values of observables, and calculate new values for non-observables. If I use observer pattern, as soon as I update first observable it notifies - could I somehow wait until all observables are updated (but possibly other observable will not change it's value at all) and only then do the recalculation?
If observables were async - it seems to me that it would be easier, I would just interrupt current calculation, and just trigger it with new values.
The output of this program is:
Changing observable id 1 from 1 -> 235
Changing NONobservable id 4 from 1 -> 236
Changing NONobservable id 3 from 1 -> 236
Changing observable id 2 from 1 -> 235
Changing NONobservable id 4 from 236 -> 470
Changing NONobservable id 3 from 236 -> 470
//notice that order of updates even metter
//so here I get this overwritten from first sync observable
Changing NONobservable id 4 from 470 -> 235
Changing NONobservable id 3 from 470 -> 235
and as you can see there is too much unneeded calls. What I wanted to have is this:
Changing observable id 1 from 1 -> 235
Changing observable id 2 from 1 -> 235
Changing NONobservable id 4 from 1 -> 470
Changing NONobservable id 3 from 1 -> 470
It is possible to have this case implemented as easy as:
void doit(){
allParts.stream()
.filter(x -> x instanceof ObservablePart)
.forEach(x -> x.updateMe(235));
Map<Integer, Part> changed = onlyNonObservableMarketsChange();
for(Part m : allParts){
m.updateMe(changed.get(m.getId()).getVal());
}
}
So, basically, instead of ObservablePart notifying Container that it's state changed, I have to put all the logic inside Container, and Container is not more dumb container that just forwards responsibility to Part objects. Now, it has to know which parts are observable and which are not, and that it first needs to update all observable parts, and only then it can do some calculations and update non-observable parts.
Is this use of observer pattern an overkill in this case? Should I just put this logic inside Container, since code and reasoning is much more straightforward?
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
public class Differ {
public static void main(String[] args) {
Container m = new Container();
m.allParts = Set.of(
new ObservablePart(1,m),
new ObservablePart(2,m),
new NonObservablePart(3),
new NonObservablePart(4)
);
m.doit();
}
}
class Container {
public Set<Part> allParts = new HashSet<>();
void doit(){
for(Part m : allParts){
m.updateMe(235);
}
}
//this would not be in Container, just needed for example
int getSumOfObservableMarkets(){
return allParts.stream()
.filter(x -> x instanceof ObservablePart)
.mapToInt(x -> ((ObservablePart) x).val)
.sum();
}
//this would not be in container, but something else would calc. changes
Map<Integer, Part> onlyNonObservableMarketsChange(){
int obsSum = getSumOfObservableMarkets();
return allParts.stream()
.collect(Collectors.toMap(k -> k.getId(), m -> {
if(m.getId()==1 || m.getId()==2){
return m;
}
m.updateMe(obsSum);
return m;
}));
}
void someObservableMarketChanged(){
Map<Integer, Part> changed = onlyNonObservableMarketsChange();
for(Part m : allParts){
m.updateMe(changed.get(m.getId()).getVal());
}
}
}
interface Part {
int getId();
int getVal();
void updateMe(int val);
}
class ObservablePart implements Part {
Container container;
ObservablePart(int id, Container m){this.id=id;
container =m;}
public int id;
int val = 1;
public int getId() {return id;}
public int getVal() {return val;}
public void updateMe(int val) {
if(this.val != val) {
System.out.printf("Changing observable id %s from %s -> %s%n", id, this.val, val);
this.val = val;
container.someObservableMarketChanged();
}
}
}
class NonObservablePart implements Part {
public int id;
int val = 1;
public NonObservablePart(int id) {this.id = id;}
public int getId() {return id;}
public int getVal() {return val;}
public void updateMe(int val) {
System.out.printf("Changing NONobservable id %s from %s -> %s%n", id, this.val, val);
this.val = val;
}
}