Open-Closed principle
Do not miss this exclusive book on Binary Tree Problems. Get it now for free.
Introduction
The open-closed principle is one the first five principles of software design, by Robert C. Martin.
The five principles where stated as follows:
S
ingle Responsibility PrincipleO
pen-Closed PrincipleL
iskov Substitution PrincipleI
nterface Segregation PrincipleD
ependency Inversion principle
They are also referred to as the SOLID design principles. These principles are necessary for the production of clear, clean, easily maintainable and extensible code.
In this article, we will to talk about the Open-Closed principle (OCP) and show examples with code.
Open-Closed principle (OCP).
Any software entity (packages, interfaces, classes, functions etc) should be:
Opened for extension:
we can introduce functionalities which were not provided during the requirements specifications
Closed for modification:
The changes introduced should not modify the existing code.
This implies that only extension of code is allowed, hence, if any software product has already been produced and shipped, any modification of its source code should be done by addition of code only.
Abstraction and Polymorphism are the tools used to achieve this. OCP is mandatory for flexible code.
Practical example with implementation
A checkers game
Consider the following class diagram of a checkers game.
The checkers game consists of a board with black and white pieces as seen in code below:
// Part of iq.opengenus.org
public class Piece{
private String colour;
private int[] position;
Piece(String colour, int[] position){
//...
}
//getters and setters...
public void setColour( String colour){
//...
}
public void setPosition( int[] position ){
//...
}
}
class WhitePiece extends Piece{
WhitePiece( String colour, int[] position ){
super(colour, position);
//...
}
}
class BlackPiece extends Piece {
BlackPiece(String colour, int[] position){
super(colour, position);
//...
}
}
The board class
// Part of iq.opengenus.org
public class Board {
protected String name;
//array of black and white pieces
protected WhitePiece[] whitePieces;
protected BlackPiece[] blackPieces;
public String getName(){
return this.name;
}
//setters...
}
class InternationalBoard extends Board{
private String name;
public void initializeBoard(){
this.getName("international Board");
//...
}
public void move( Piece piece, int[] destination){
// the board move pieces following its rules
//...
// other functions jump etc
//
}
class AustralianBoard extends Board{
public void jump( Piece piece, int x, int y){
// a jump is done in a particular way for particular board
}
public void initializeBoard(){
//...
}
public void move( Piece piece, int[] destination){
// the board move pieces following its rules
//...
// other functions jump etc
//
}
and finally the checkers class
// Part of iq.opengenus.org
public class Checkers {
private String name;
private Board board;
private String player1;
private String player2;
//constructor
void game(Board board){
if ( board instanceof InternationalBoard){
//game starts following the rules of internationBoard
}
else if ( board instanceof AustralianBoard ){
//game starts following the rules of Australian board
}
}
}
From the code, we notice that if we want to extend our checkers app, lets say for instance we want to add the chinese board, we will have to add class ChineseBoard {}
and modify the class the Checkers class
(adding another else if clause and new code for the rules of the chinese board).Furthermore it would be much more difficult to add higher number of boards since this implies increasing the risk of introducing errors into the Checkers class. The open-closed principle is not respected; Checkers
is opened for extension but not closed for modification.
This is a better way to model respecting the OCP principle:
The Board class can be abstracted, here we declare the game method, which is overridden by a particular board's game()
.
// Part of iq.opengenus.org
abstract class Board {
private String name;
protected WhitePiece[] WhitePieces;
//getters and setters
public String getName(){
return this.name;
}
public void setName(String name){
this.name = name;
}
abstract void game();
}
class InternationalBoard extends Board {
@Override
public void game(){
//play following internation checkers rules
}
public void jump( Piece piece, int x, int y){
// a jump is done in a particular way for particular board
}
public void initializeBoard(){
this.setName("International Board");
//...
}
}
class AustralianBoard extends Board{
public void jump( Piece piece, int x, int y){
// a jump is done in a particular way for particular board
}
@Override
public void game(){
}
public void initializeBoard(){
this.setName("Australian Board");
//...
}
}
public class Checkers {
private String player1;
private String player2;
//getters and setters
public String getPlayer1(){
return this.player1;
}
public String getPlayer2(){
return this.player2;
}
void play(Board currentBoard){
currentBoard.game();
}
}
The modified version of the model allows addition of new boards without modifying any existing class, the above code is opened for extension and closed for modification, respecting the OCP principle.
Conclusion
Knowing how to apply this principle is very important in software design. It helps to write clear, flexible and extensible code, Hence should always be applied as well as the four other principles.
Sign up for FREE 3 months of Amazon Music. YOU MUST NOT MISS.