Object-oriented – Do you leverage the benefits of the open-closed principle

Architecturedesigndesign-patternsobject-oriented

The open-closed principle (OCP) states that an object should be open for extension but closed for modification. I believe I understand it and use it in conjunction with SRP to create classes that do only one thing. And, I try to create many small methods that make it possible to extract out all the behavior controls into methods that may be extended or overridden in some subclass. Thus, I end up with classes that have many extension points, be it through: dependency injection and composition, events, delegation, etc.

Consider the following a simple, extendable class:

class PaycheckCalculator {
    // ...
    protected decimal GetOvertimeFactor() { return 2.0M; }
}

Now say, for example, that the OvertimeFactor changes to 1.5. Since the above class was designed to be extended, I can easily subclass and return a different OvertimeFactor.

But… despite the class being designed for extension and adhering to OCP, I'll modify the single method in question, rather than subclassing and overridding the method in question and then re-wiring my objects in my IoC container.

As a result I've violated part of what OCP attempts to accomplish. It feels like I'm just being lazy because the above is a bit easier. Am I misunderstanding OCP? Should I really be doing something different? Do you leverage the benefits of OCP differently?

Update: based on the answers it looks like this contrived example is a poor one for a number of different reasons. The main intent of the example was to demonstrate that the class was designed to be extended by providing methods that when overridden would alter the behavior of public methods without the need for changing internal or private code. Still, I definitely misunderstood OCP.

Best Answer

If you are modifying the base class then it is not really closed is it!

Think of the situation where you have released the library to the world. If you go and change the behavior of your base class by modifying the overtime factor to 1.5 then you have violated all the people that use your code assuming that the class was closed.

Really to make the class closed but open you should be retrieving the overtime factor from an alternative source (config file maybe) or proving a virtual method that can be overridden?

If the class was truly closed then after your change no test cases would fail (assuming you have 100% coverage with all your test cases) and I would assume that there is a test case that checks GetOvertimeFactor() == 2.0M.

Don't over Engineer

But don't take this open-close principle to the logical conclusion and have everything configurable from the start (that is over engineering). Only define the bits you currently need.

The closed principle does not preclude you from re-engineering the object. It just pre-cludes you from changing the currently defined public interface to your object (protected members are part of the public interface). You can still add more functionality as long as the old functionality is not broken.