Reputation: 468
Scenario: I stored some information (e.g. an array of doubles) in a class field (say field Measurements
, array of integers in a class MeasureData
). Now I would like to use this data to perform some calculations (e.g compute the arithmetic mean of the array, the maximum and the minimum). At the moment, I don't know if in the future I'll need to do any other operation on those data (e.g. maybe I will need to get the standard deviation, the sum or whatever). I'll have many objects of type MeasureData
.
Solution: I could write a class Calculator
, declare it final, use a private constructor and use several static methods to perform the calculations I need. This seems to make sense, since Calculator
acts as an utility class, without any field, much like the standard Math
class.
Problem: if, in a couple of months, I'll need to do any other calculation, I'll be needing to write another static method in Calculator
. Does this mean to violate the open/closed principle (after all, I'm modifying the implementation of the class Calculator
)?
Upvotes: 5
Views: 1880
Reputation: 1759
The strict answer is yes; OCP states that a class is open for extension but closed for modification. You would be modifying Calculator
, and, hence, violating OCP (as you've already concluded).
This leads to two points:
First, is violating OCP a big deal in this case? You're additively changing Calculator
to add a new method to it. Calculator
is a static helper class used to get meaningful data from your objects. Adding a new method, like calculating SD, is not going to affect any of the other operations within it. With a proper implementation, is there really a way that adding this method could compromise your project?
Second, if you feel like the OCP violation is not acceptable, then this is a textbook example of where Strategy Pattern can be utilized. Consider:
Measurements.Java
public class Measurements {
private int[] data;
public Measurements(int[] data) {
this.data = data;
}
public Number performCalculation(Calculation c) {
return c.performCalculation(data);
}
}
Calculation.java
public interface Calculation {
Number performCalculation(int[] data);
}
You can then make a calculation class for each different calculation you want to do on the data (eg: MeanCalculation
, StdDevCalculation
, etc.). If you want a new calculation (eg: MedianCalculation
), you can make this without modifying any of the other code in this area (closed for modification, open for extension; OCP compliant). The end result looks like:
Measurements values = ...
Number mean = values.performCalculation(new MeanCalculation());
Number SD = values.performCalculation(new StdDevCalculation());
// etc.
I'm not saying this is the best approach (or best implementation of the approach even) for your specific case; you need to answer that for yourself. But I hope this answer provides a decent external perspective on the matter.
Upvotes: 8