This is the second part of my explanation of the SOLID principles in software engineering. My previous post covered the Single Responsibility Principle (SRP) and you should read that before this one if you have not already done so. We are going to touch briefly on SRP as you’ll soon find that these principles really tend to bleed together, and in many ways are a heuristic for quality code, rather than a firm rule. You can violate these, but at a cost, and sometimes that’s ok.
Open Closed Principle (OCP)
This principle basically says that our code (classes and methods) should be open to extension, but closed to modification. You may be wondering what exactly this means, but let me explain first with words, and then later we’ll use an example again using C#, and as I said previously, this is by no means only going to apply to this specific language. These apply to all object-oriented languages. In our previous example, we were using customers as an example and we wanted to send them an email. What if though we wanted to change the way in which we were going to send our customers a message? What if we wanted to send them a text message? Would we want to change our
SendEmailMethod(...) to also be able to send text messages? No, as this would violate the Single Responsibility Principle. So chances are we are going to create a new class, with a new method. And we also want to be able to use these methods somewhat interchangeably and have a similar implementation. This is where the Open Closed Principle comes to the rescue. Look at the code below. You should recognize our customer class from the previous post. We also have added a
Message abstract class, if you are unfamiliar with inheritance I’d suggest following up and learning about this, any object-oriented language will use this extensively and the other SOLID principles hereafter use this feature extensively. From our abstract
Message class we are creating to child message classes. These are the extension of our base class. We haven’t touched on the Liskov Substitution Principle, that’s next, but this is also using inheritance, and being explicit about how it’s used. More on that later. For now, read through the code below.
Running the above code will have the below output:
Sending Nick a text message Sending Billy an email Sending Jenny a text message
Here in this example of the OCP, we are using abstraction to our advantage, this allows us to have a base class implementation and then following that if we want to make a change we can create a new implementation. Our code is open to extension, but the classes are closed for change. For example, if we wanted to have a
SendGoogleChatMessage class we could use the same base
Message class and then create child class from that. Notice that our classes are small, I know this is only an example, but in real life code, when using solid principles, our classes tend to stay small. Another heuristic in this regard in my experience are classes over about 250 lines tend to violate this principle (and usually the other SOLID principles as well)
When Do We Not Want to Implement OCP?
I think that there are times when using SOLID principles may be a bit overkill, especially if the project is maybe a simple console application, that we know is going to be used only for a couple of things, or meant to be used only once. However, if we write our code from the beginning so that it can be easily understood, without using SOLID Principles, usually it’s going to be easily refactored and if need, when requirements keep changing, then start using OCP. However, if you have an understanding of the requirements and understand from the get-go that things are subject to change, then you really ought to take into consideration the Open Closed Principle. This is a pretty simple implementation, and as I said the LSP (Liskov Substitution Principle) is next.
Benefits of using OCP
There is definitely an upside to using OCP in our design upfront, these benefits include:
- Code flexibility
- Easier testing of our code, in that we only have to write tests for our new implementations (also using SRP)
- Fewer bugs, especially if we are not having to touch our original code.
Thanks for reading, and hope you gained some new insight!