I understand the intent of the open-closed principle. It's meant to reduce the risk of breaking something that already works while modifying it, by telling you to try to extend without modifying.
However, I had some trouble understanding how this principle is applied in practice. To my understanding, there are two ways to apply it. Beofore and after a possible change:
Before: program to abstractions and 'predict the future' as much as you can. For example, a method
drive(Car car)will have to change if
Motorcycles are added to the system in the future, so it probably violates OCP. But the method
drive(MotorVehicle vehicle)is less likely to have to change in the future, so it adheres to OCP.
However, it's quite difficult to predict the future and know in advance what changes are going to be made to the system.
After: when a change is needed, extend a class instead of modifying it's current code.
Practice #1 isn't hard to understand. However it's practice #2 that I'm having trouble understanding how to apply.
For example (I took it from a video on YouTube): let's say we have a method in a class that accepts
makePayment(CraditCard card). One day
Vouchers are added to the system. This method doesn't support them so it has to be modified.
When implementing the method in the first place we failed to predict the future and program in more abstract terms (e.g.
makePayment(Payment pay), so now we have to change the existing code.
Practice #2 says we should add the functionality by extending instead of modifying. What does that mean? Should I subclass the existing class instead of simply changing it's existing code? Should I make some kind of wrapper around it just to avoid rewriting code?
Or does the principle not even refer to 'how to correctly modify/add functionality', but rather refers to 'how to avoid having to make changes in the first place (i.e. program to abstractions)?