The open-closed principle says that a class should be opened for extension and closed for modification. What does that mean?
A class should be made easy to add features and hard to alter its core function.
Suppose that you need to write a password validator for a user creation flow. You already have a
CreateUser class. What can you do?
You can create a password validation method inside the
CreateUser class, but that would violate the Single Responsibility principle. You should separate the validation responsibility from the
CreateUser class. You can create a
ValidatePassword class to accomplish this. Great, that should do it!
ValidatePassword class is not really that flexible. This class can only validate a password input. An even more flexible solution would be to create a
Validate class with a
password method inside it. In the future, if you need to add more validation logic, you can just extend this
Validate class with more methods like
username to validate user email and username!
Let's imagine what would have happened if you had created
ValidatePassword. In the future if you need to validate email and username, you will have to create
ValidateUsername classes. I will bet you two boxes of donuts that there will be plenty of duplicate codes (
ValidatePassword mostly do the same thing).
I understand that upcoming features are often unprecedented. Some classes are more subtle and harder to spot for reusability. Maybe the PM assured you last month that the only validation you would ever need was
ValidatePassword, so you created that class naively believing that there was no need to extend it in the future. However, this week your PM told you that you needed to validate email and username after all! No worries, as long as you catch them early on, you could easily abstract it and create the
This is the "open" part of the open-closed principle: the
Validate class is open for extension. Each time you need to extend the feature, just add a new interface. Need an email validation? Add an email interface. Need a username validation? Add a username interface.
What about the "closed" part of the open-closed principle? By definition, a class is closed. In practice, you would create an instance of that class object, something like
passwordValidator = new Validate("password").
Once a class is defined, no one should alter it. The
Validate class validates different attributes. That's it. If you decided that the
Validate class should start saving password into the database, then you violated the "closed" part (you also violated the single-responsibility principle).
By keeping the open-closed principle, anyone who depends on
passwordValidator won't receive surprise bugs.
Anytime you start thinking, "Hey, I've written codes like this before...", it's a good chance that you can create an extensible, more abstract class.