Skip to content

Commit 0720704

Browse files
committed
refactor: extract Totaler class to gather common code
1 parent 591f03d commit 0720704

File tree

4 files changed

+113
-108
lines changed

4 files changed

+113
-108
lines changed

measure/src/main/java/net/laprun/sustainability/power/analysis/total/TotalMeasureProcessor.java

Lines changed: 9 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,46 @@
11
package net.laprun.sustainability.power.analysis.total;
22

3-
import java.util.Arrays;
4-
import java.util.Objects;
5-
import java.util.function.Function;
6-
import java.util.stream.Collectors;
7-
8-
import net.laprun.sustainability.power.Errors;
93
import net.laprun.sustainability.power.SensorMetadata;
104
import net.laprun.sustainability.power.SensorUnit;
115
import net.laprun.sustainability.power.analysis.MeasureProcessor;
126

137
public class TotalMeasureProcessor implements MeasureProcessor {
14-
private final String name;
8+
private final Totaler totaler;
159
private double minTotal = Double.MAX_VALUE;
1610
private double maxTotal;
1711
private double accumulatedTotal;
18-
private final Function<double[], Double> formula;
19-
private final SensorUnit expectedResultUnit;
2012

2113
public TotalMeasureProcessor(SensorMetadata metadata, SensorUnit expectedResultUnit, int... totalComponentIndices) {
22-
Objects.requireNonNull(totalComponentIndices, "Must specify component indices that will aggregated in a total");
23-
this.expectedResultUnit = Objects.requireNonNull(expectedResultUnit, "Must specify expected result unit");
24-
25-
final var errors = new Errors();
26-
final var totalComponents = Arrays.stream(totalComponentIndices)
27-
.mapToObj(i -> toTotalComponent(metadata, i, errors))
28-
.toArray(TotalComponent[]::new);
29-
name = Arrays.stream(totalComponents)
30-
.map(TotalComponent::name)
31-
.collect(Collectors.joining(" + ", "Aggregated total from (", ")"));
32-
formula = components -> {
33-
double result = 0;
34-
for (var totalComponent : totalComponents) {
35-
result += components[totalComponent.index] * totalComponent.factor;
36-
}
37-
return result;
38-
};
39-
40-
if (errors.hasErrors()) {
41-
throw new IllegalArgumentException(errors.formatErrors());
42-
}
43-
}
44-
45-
private TotalComponent toTotalComponent(SensorMetadata metadata, int index, Errors errors) {
46-
final var cm = metadata.metadataFor(index);
47-
final var name = cm.name();
48-
final var unit = cm.unit();
49-
if (!unit.isCommensurableWith(expectedResultUnit)) {
50-
errors.addError("Component " + name
51-
+ " is not commensurable with the expected base unit: " + expectedResultUnit);
52-
}
53-
54-
final var factor = unit.factor();
55-
return new TotalComponent(name, index, factor);
14+
this.totaler = new Totaler(metadata, expectedResultUnit, totalComponentIndices);
15+
totaler.validate();
5616
}
5717

5818
public double total() {
59-
return convertToExpectedUnit(accumulatedTotal);
19+
return accumulatedTotal;
6020
}
6121

6222
public double minMeasuredTotal() {
63-
return minTotal == Double.MAX_VALUE ? 0.0 : convertToExpectedUnit(minTotal);
23+
return minTotal == Double.MAX_VALUE ? 0.0 : minTotal;
6424
}
6525

6626
public double maxMeasuredTotal() {
67-
return convertToExpectedUnit(maxTotal);
68-
}
69-
70-
private double convertToExpectedUnit(double value) {
71-
return value * expectedResultUnit.base().conversionFactorTo(expectedResultUnit);
72-
}
73-
74-
private record TotalComponent(String name, int index, double factor) {
27+
return maxTotal;
7528
}
7629

7730
@Override
7831
public String name() {
79-
return name;
32+
return totaler.name();
8033
}
8134

8235
@Override
8336
public String output() {
84-
final var symbol = expectedResultUnit.symbol();
37+
final var symbol = totaler.expectedResultUnit().symbol();
8538
return String.format("%.2f%s (min: %.2f / max: %.2f)", total(), symbol, minMeasuredTotal(), maxMeasuredTotal());
8639
}
8740

8841
@Override
8942
public void recordMeasure(double[] measure, long timestamp) {
90-
final double recordedTotal = formula.apply(measure);
43+
final double recordedTotal = totaler.computeTotalFrom(measure);
9144
accumulatedTotal += recordedTotal;
9245
if (recordedTotal < minTotal) {
9346
minTotal = recordedTotal;
Lines changed: 6 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,35 @@
11
package net.laprun.sustainability.power.analysis.total;
22

3-
import java.util.Arrays;
4-
import java.util.Objects;
5-
import java.util.function.Function;
6-
import java.util.stream.Collectors;
7-
8-
import net.laprun.sustainability.power.Errors;
93
import net.laprun.sustainability.power.SensorMetadata;
104
import net.laprun.sustainability.power.SensorUnit;
115
import net.laprun.sustainability.power.analysis.SyntheticComponent;
126

137
public class TotalSyntheticComponent implements SyntheticComponent {
14-
private final Function<double[], Double> formula;
15-
private final SensorUnit expectedResultUnit;
8+
private final Totaler totaler;
169
private final SensorMetadata.ComponentMetadata metadata;
1710

1811
public TotalSyntheticComponent(SensorMetadata metadata, SensorUnit expectedResultUnit, int... totalComponentIndices) {
19-
Objects.requireNonNull(totalComponentIndices, "Must specify component indices that will aggregated in a total");
20-
this.expectedResultUnit = Objects.requireNonNull(expectedResultUnit, "Must specify expected result unit");
21-
22-
final var errors = new Errors();
23-
final var totalComponents = Arrays.stream(totalComponentIndices)
24-
.mapToObj(i -> toTotalComponent(metadata, i, errors))
25-
.toArray(TotalComponent[]::new);
26-
final String name = Arrays.stream(totalComponents)
27-
.map(TotalComponent::name)
28-
.collect(Collectors.joining(" + ", "total (", ")"));
12+
this.totaler = new Totaler(metadata, expectedResultUnit, totalComponentIndices);
2913
final var isAttributed = metadata.components().values().stream()
3014
.map(SensorMetadata.ComponentMetadata::isAttributed)
3115
.reduce(Boolean::logicalAnd).orElse(false);
32-
formula = components -> {
33-
double result = 0;
34-
for (var totalComponent : totalComponents) {
35-
result += components[totalComponent.index] * totalComponent.factor;
36-
}
37-
return result;
38-
};
39-
16+
final var name = totaler.name();
4017
if (metadata.exists(name)) {
41-
errors.addError("Component " + name + " already exists");
18+
totaler.addError("Component " + name + " already exists");
4219
}
4320

44-
if (errors.hasErrors()) {
45-
throw new IllegalArgumentException(errors.formatErrors());
46-
}
21+
totaler.validate();
4722

4823
this.metadata = new SensorMetadata.ComponentMetadata(name, "Aggregated " + name, isAttributed, expectedResultUnit);
4924
}
5025

51-
private double convertToExpectedUnit(double value) {
52-
return value * expectedResultUnit.base().conversionFactorTo(expectedResultUnit);
53-
}
54-
55-
private record TotalComponent(String name, int index, double factor) {
56-
}
57-
58-
private TotalComponent toTotalComponent(SensorMetadata metadata, int index, Errors errors) {
59-
final var cm = metadata.metadataFor(index);
60-
final var name = cm.name();
61-
final var unit = cm.unit();
62-
if (!unit.isCommensurableWith(expectedResultUnit)) {
63-
errors.addError("Component " + name
64-
+ " is not commensurable with the expected base unit: " + expectedResultUnit);
65-
}
66-
67-
final var factor = unit.factor();
68-
return new TotalComponent(name, index, factor);
69-
}
70-
7126
@Override
7227
public SensorMetadata.ComponentMetadata metadata() {
7328
return metadata;
7429
}
7530

7631
@Override
7732
public double synthesizeFrom(double[] components, long timestamp) {
78-
return convertToExpectedUnit(formula.apply(components));
33+
return totaler.computeTotalFrom(components);
7934
}
8035
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package net.laprun.sustainability.power.analysis.total;
2+
3+
import java.util.Arrays;
4+
import java.util.Objects;
5+
import java.util.function.Function;
6+
import java.util.stream.Collectors;
7+
8+
import net.laprun.sustainability.power.Errors;
9+
import net.laprun.sustainability.power.SensorMetadata;
10+
import net.laprun.sustainability.power.SensorUnit;
11+
12+
class Totaler {
13+
private final SensorUnit expectedResultUnit;
14+
private final Function<double[], Double> formula;
15+
private final String name;
16+
private Errors errors;
17+
18+
Totaler(SensorMetadata metadata, SensorUnit expectedResultUnit, int... totalComponentIndices) {
19+
Objects.requireNonNull(totalComponentIndices, "Must specify component indices that will aggregated in a total");
20+
this.expectedResultUnit = Objects.requireNonNull(expectedResultUnit, "Must specify expected result unit");
21+
22+
errors = new Errors();
23+
final var totalComponents = Arrays.stream(totalComponentIndices)
24+
.mapToObj(i -> from(metadata, i, expectedResultUnit, errors))
25+
.toArray(TotalComponent[]::new);
26+
name = Arrays.stream(totalComponents)
27+
.map(TotalComponent::name)
28+
.collect(Collectors.joining(" + ", "total (", ")"));
29+
formula = formulaFrom(totalComponents);
30+
}
31+
32+
void validate() {
33+
if (errors.hasErrors()) {
34+
throw new IllegalArgumentException(errors.formatErrors());
35+
}
36+
errors = null;
37+
}
38+
39+
public void addError(String message) {
40+
if (errors == null) {
41+
throw new IllegalStateException("Totaler has already been validated!");
42+
}
43+
errors.addError(message);
44+
}
45+
46+
public String name() {
47+
return name;
48+
}
49+
50+
public SensorUnit expectedResultUnit() {
51+
return expectedResultUnit;
52+
}
53+
54+
public double computeTotalFrom(double[] measure) {
55+
checkValidated();
56+
return convertToExpectedUnit(formula.apply(measure));
57+
}
58+
59+
private void checkValidated() {
60+
if (errors != null) {
61+
throw new IllegalStateException("Totaler must be validated before use!");
62+
}
63+
}
64+
65+
private double convertToExpectedUnit(double value) {
66+
return value * expectedResultUnit.base().conversionFactorTo(expectedResultUnit);
67+
}
68+
69+
private record TotalComponent(String name, int index, double factor) {
70+
double scaledValueFrom(double[] componentValues) {
71+
return componentValues[index] * factor;
72+
}
73+
}
74+
75+
private static TotalComponent from(SensorMetadata metadata, int index, SensorUnit expectedResultUnit, Errors errors) {
76+
final var cm = metadata.metadataFor(index);
77+
final var name = cm.name();
78+
final var unit = cm.unit();
79+
if (!unit.isCommensurableWith(expectedResultUnit)) {
80+
errors.addError("Component " + name
81+
+ " is not commensurable with the expected base unit: " + expectedResultUnit);
82+
}
83+
84+
final var factor = unit.factor();
85+
return new TotalComponent(name, index, factor);
86+
}
87+
88+
private static Function<double[], Double> formulaFrom(TotalComponent[] totalComponents) {
89+
return components -> {
90+
double result = 0;
91+
for (var totalComponent : totalComponents) {
92+
result += totalComponent.scaledValueFrom(components);
93+
}
94+
return result;
95+
};
96+
}
97+
}

measure/src/test/java/net/laprun/sustainability/power/measure/StoppedPowerMeasureTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public String output() {
9393
final var output = PowerMeasure.asString(stopped);
9494
assertThat(output).contains(stoppedCompProcOutput, stoppedMeasureOutput, ongoingCompProcOutput);
9595
// second anonymous class
96-
assertThat(output).contains(stoppedCompProcName, stoppedMeasureProcName, "Aggregated total from (cp1)",
96+
assertThat(output).contains(stoppedCompProcName, stoppedMeasureProcName, "total (cp1)",
9797
getClass().getName() + "$2");
9898
assertThat(output).contains("0.00mW");
9999
assertThat(output).doesNotContain("Infinity");

0 commit comments

Comments
 (0)