Gabriele
Gabriele

Reputation: 468

Am I violating the "open/closed" principle?

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

Answers (1)

Ironcache
Ironcache

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

Related Questions