The open / closed principle prizes basically for not spoiling what is already ready. That is, think of your preferred programming language, now suppose you have numerous applications developed in this language, however one fine day comes a newer version of this language and you are obliged to come back repairing all your applications developed to the present moment since the language simply changed the way we did something and did not give continuity to the old way of doing it. Now multiply this by all the developers of that language around the globe. Have you thought about the chaos this would generate?
In smaller proportions we also develop codes that can be used by other classes of ours in other applications or even used by other people.
An excellent (simplified) example of avoiding hurting this principle is getters and setters.
Example: You made a code without the getters and setters, however you noticed that some of the attributes of your class need a validation, let's say any date that can not be defined as before the current date, since in fact it should referring to something in the future. That is, you should not allow something like this:
material.dataPrevistaDeChegada = new DateTime("01/01/2014");
To fix this you resolve to get and set to the date field and change public access to private. By doing this all the codes that made access to the attribute directly will be broken, because it is no longer possible to access the attribute the way it was done before.
However, if the attribute has always been private and has always had the get and the set nothing prevents you from implementing the value check before changing your date, so you only have to improve your code without breaking the code of the other classes .
Code example using the set without thinking about validation:
public void setDataPrevistaDeChegada(DateTime dataPrevistaDeChegada) {
this.dataPrevistaDeChegada = dataPrevistaDeChegada;
}
Code when you first noticed that validation was important:
public void setDataPrevistaDeChegada(DateTime dataPrevistaDeChegada) {
if(dataPrevistaDeChegada.isBefore(new DateTime(DateTime.now()))) {
return;
}
this.dataPrevistaDeChegada = dataPrevistaDeChegada;
}
The return
is just an example, if you want you can assign a default value as long as this is acceptable for your application.
In the example above you have extended your code, but you have not changed it. Okay, in practice you made a change, but this modification is transparent to those who depend on your class, so you can change internal details as long as that does not affect who depends on your class, this would be called extension rather than change.
By modifying the set, you have ensured that the date attribute will not change if the condition placed within the set is not met, this example is just a good simplification of how not to hurt the principle, worth being quoted as being broadly known among developers.
More advanced solutions to ensure the open / closed principle would basically be a more elaborate modeling of your classes, such as the Factory Design Pattern, which is an intermediate between the class you want a new class instance and the class that will provide this new object. Inside the Factory you put the rules of creation of the object, in case one day you need to change these rules you can do without making them modify the classes that depend on it.