This article explains the open closed principle, one of the SOLID Design Principles, with example in Java.
Open/Closed Principle – by Bertrand Meyer
Open/Closed Principle was originally defined by Bertrand Meyer in his book Object Oriented Software Construction. Bertrand Meyer’s definition was divided into 3 statements.The first 2 statements defined the notions of Open & Closed modules(or classes) –
1st statement – As per Meyer a module is Open when – A module will be said to be open if it is still available for extension. For example, it should be possible to add fields to the data structures it contains, or new elements to the set of functions it performs.
What it means – If attributes or behavior can be added to a class it can be said to be “open”.
2nd statement – As per Meyer a module is Closed when – A module will be said to be closed if it is available for use by other modules. This assumes that the module has been given a well-defined, stable description (the interface in the sense of information hiding).
What it means – If a class is re-usable or specifically available for extending as a base class then it is closed. One of the basic requirements for a class to be closed in this way is that its attributes and methods should be finalized because if they change all the classes which inherit the base class are affected.
Meyer’s third statement gave the final shape to the Open/Closed principle which is so much in practice in Object Oriented Programming.
3rd statement – Meyer defined that a class adheres to the Open/Closed Principle when – the class is closed, since it may be compiled, stored in a library, baselined, and used by client classes. But it is also open, since any new class may use it as parent, adding new features. When a descendant class is defined, there is no need to change the original or to disturb its clients.
What it means – A class can be open and closed at the same time. To elaborate on this further, we need to next consider the previous two statements by Meyer where he describes the conditions for a class to be Open and Closed together.
Conditions for a class to be Open & Closed together (and satisfy the Open/Closed Principle)
- A class can be considered to be closed if its runtime or compiled class is available for use as a base class which can be extended by child classes. Baselining here refers to making sure that changes are guaranteed to not happen. In short – The said class is open for extension.
- A class can be considered to be open if its functionality can be enhanced by sub-classing it. When a class is a sub-class then by using the Liskov Substitution rule it can be replaced by its sub-class. This sub-class behaves as its parent class but is an enhanced version of it. In short – The said class is open for modification(via extension).
Example of Open/Closed Principle in Java
Lets say we need to calculate areas of various shapes. We start with creating a class for our first shape
Rectangle which has 2 attributes
Next we create a class to calculate area of this
Rectangle which has a method
calculateRectangleArea() which takes the
Rectangle as an input parameter and calculates its area –
Circlewith a single attribute
Then we modify
AreaCalculatorclass to add circle calculations through a new method
However, note that there were flaws in the way we designed our solution above.
Lets say we have a new shape pentagon next. In that case we will again end up modifying
AreaCalculator class. As the types of shapes grows this becomes messier as
AreaCalculator keeps on changing and any consumers of this class will have to keep on updating their libraries which contain
AreaCalculator. As a result,
AreaCalculator class will not be baselined(finalized) with surety as every time a new shape comes it will be modified. So, this design is not closed for modification.
Also, note that this design is not extensible, i.e what if complicated shapes keep coming,
AreaCalculator will need to keep on adding their computation logic in newer methods. We are not really expanding the scope of shapes; rather we are simply doing piece-meal(bit-by-bit) solution for every shape that is added.
Modification of above design to comply with Open/Closed Principle
Let us now see a more elegant design which solves the flaws in the above design by adhering to the Open/Closed Principle. We will first of all make the design extensible. For this we need to first define a base type
Shape and have
Shape interface –
- There is a base interface
Shape. All shapes now implement the base interface
- Shape interface has an abstract method
calculateArea(). Both circle & rectangle provide their own overridden implementation of
calculateArea()method using their own attributes.
- We have brought-in a degree of extensibility as shapes are now an instance of Shape interfaces. This allows us to use
Shapeinstead of individual classes wherever these classes are used by any consumer.
The last point above mentioned consumer of these shapes. In our case consumer will be the
AreaCalculator class which would now look like this –
AreaCalculatorclass now fully removes our design flaws noted above and gives a clean solution which adheres to the Open-Closed Principle.
The design is now correct as per Open Closed Principle due to the following reasons –
- The design is open for extension as more shapes can be added without modifying the existing code. We just need to create a new class for the new shape and implement the
calculateArea()method with a formula specific to that new shape.
- This design is also closed for modification.
AreaCalculatorclass is complete w.r.t area calculations. It now caters to all the shapes which exists now, as well as to those that may be created later.
In the above tutorial we learnt what is Open Closed Principle by definition, then elaborated on that definition. We then saw an example of java code which was flawed in its design. Lastly, we made the design good by making it adhere to the Open Closed Principle.