Open Closed Principle of SOLID | OCP
SOLID Principles are one of the mandatory question in each and every interview. This is the third part of the SOLID Design Principle. In this part, we will walk through the second SOLID Design Principle i.e Open Closed Principle (OCP) in detail with live real examples.
Please read the previous parts over here below links:
Single Responsibility Principle
Introduction
In the SOLID acronym, the second letter "O" represents the "Open Closed Principle". The Open-Closed Principle focuses on the behavior of a class or module in case of modification and extension.
When a single change in a program results in a cascade of changes to the dependent modules it is considered a "bad design". The program becomes fragile, rigid, unpredictable, and unreusable. The open-closed principle is the root motivation behind many of the heuristics and conventions that have been published regarding OOD over the years.
This principle states that you should design modules that never change. When requirements change, you extend the behavior of such modules by adding new code, not by changing old code that already works.
The Open-Closed Principle encourages the developers to design and write the code in such a way that adding new functionality would involve minimal changes to existing code. Most of the changes should be handled in new methods and new classes only instead of the original one.
Open-Closed Principle (OCP)
The Open-Closed Principle is the second SOLID Design Principle. The Open-Closed Principles is first proposed by Bertrand Meyer in his book "Object-Oriented Software Construction" in the year 1988 but it was updated by Robert C. Martin later in the 1990s.
As per Ivar Jacobson in his book "Object-Oriented Software Engineering a Use Case Driven Approach":
"All systems change during their life cycles. This must be borne in mind when developing systems expected to last longer than the first version."
How can we create designs that are stable in the face of change and that will last longer than the first version? So Bertrand Meyer gave us guidance to achieve this in his Open Closed Principle.
Definition of OCP
The Open-Closed Principle said that classes should be open for extension and closed to modification. Here modification means changing the code of an existing class, and extension means adding new functionality.
According to Bertrand Meyer, the Open-Closed Principle states that:
Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification.
Here Modification means changing the code of an existing class, module, or function, and Extension means adding new functionality or behavior.
In other words:
"Class should be extendable without modifying the class itself."
But here the "extension" does not mean the extending in java or inheritance in C# only at all. This definition is given before the evolution of C++, Java, and C#. What it means here is that a module should provide extension points to alter its behavior.
So, we should be able to add new functionality without touching the existing code for the class or module because whenever we modify the existing code, we are taking the risk of creating potential bugs.
Modules following the Open-Closed Principle must have two primary attributes:
1. They are “Open For Extension”: The behavior of the module can be extended i.e we can make the module behave in new and different ways as the requirements of the application change.
2. They are “Closed for Modification”: The source code of such a module is inviolate i.e No one is allowed to make source code changes to it.
How can we change the behavior of a module without making changes to it? The statement is looking contradictory but not actually. The solution is an abstraction.
Please watch the Fragile Base Class Problem video here.
Mayer's Open Closed Principle: Inheritance Based OCP
Mayer provides the Open-Closed Principle based on inheritance so the actual definition given by Mayer is Inheritance Based Open-Closed Principle. So he proposed to use inheritance to achieve this goal.
Since Bertrand Mayer proposes the Inheritance Based Open-Closed Principle to achieve this goal, and inheritance introduces tight coupling if the subclasses depend on implementation details of their parent class.
So the concrete class inheritance leads to a lot of problems, which is realized by Robert C. Martin. So he proposed a new version of the Open-Closed Principle definition in his book "Object-Oriented Software Construction".
Martin's Open Closed Principle: Polymorphic OCP
Robert C. Martin redefined the Open-Closed Principle to the Polymorphic Open-Closed Principle.
In contrast to Meyer's definition, this definition advocates inheritance from abstract base classes or interfaces. Interface specifications can be reused through inheritance but implementation need not be.
You should be able to extend the behavior of a system without having to modify that system.
Please read the Polymorphic Dilemma over here:
Method Overloading and Overloading Dilemma - Part 1
Method Overloading and Overloading Dilemma - Part 2
Method Overloading and Overloading Dilemma - Part 3
Explanation
A module or class is said to be open if it is still available for the extension means new fields, properties, or functions can be added on which it performs.
A module or class is said to be closed if it is available only for use by other modules or classes means the module has been given a well-defined, stable description.
A class is closed, since it may be compiled, stored in a library, baselined, and used by many client classes. But at the same time, it is also open, since any new class may use it as a parent class, adding new features into it. By doing so, there is no need to change the original base class or to disturb its clients.
Implementation Guidelines for Open-Closed Principle:
So during the 1990s, the Open-Closed Principle was redefined to use abstracted interfaces, where the implementations can be changed and multiple implementations could be created and polymorphically substituted for each other.
The abstractions are abstract base classes or interfaces, and the unbounded group of possible behaviors is represented by all the possible derivative classes that implement them. Such a module can be closed for modification since it depends upon an abstraction that is fixed. The behavior of that module can be extended by creating new derivatives of the abstraction and it is possible for a derived module to manipulate an abstraction.
But the Open-Closed Principle can also be achieved in many other ways, including through the use of inheritance or through composition or composite design patterns like the Strategy Pattern.
Please watch the Inheritance vs Composition video here.
One way is to make use of polymorphism to invoke extended behaviors of an object at run time. It also uses interfaces instead of SuperClasses to allow different implementations which you can easily substitute without changing the code that uses them.
The existing interface is closed to modifications and new implementations must, at least minimum, implement that interface. The interfaces are closed for modifications, and you can provide new implementations to extend the functionality of your software. But no significant program can be 100% closed.
Heuristics and Conventions for OCP:
1. All the Member Variables must be Private
2. No Global Variables Ever
3. No Run Time Type Identification (RTTI)
Example
public class Report
{
public TemplateBody GetTemplate(string clientName, ReportType reportType)
{
TemplateBody template = new TemplateBody();
if (reportType == ReportType.FullReport)
{
template.TemplateType = TemplateType.TemplateFull;
template.ClientName = clientName;
template.Date = DateTime.Now;
}
else if (reportType == ReportType.PartialReport)
{
template.TemplateType = TemplateType.TemplatePartial;
template.ClientName = clientName;
template.Date = DateTime.Now;
}
return template;
}
}
public enum ReportType
{
FullReport = 1,
PartialReport = 2
};
public enum TemplateType
{
TemplateFull = 1,
TemplatePartial = 2
};
public class TemplateBody
{
public TemplateType TemplateType { get; set; }
public string ClientName { get; set; }
public DateTime Date { get; set; }
}
interface IReport
{
TemplateBody GetTemplate(string clientName);
}
public class FullReport : IReport
{
public TemplateBody GetTemplate(string clientName)
{
TemplateBody template = new TemplateBody();
template.TemplateType = TemplateType.TemplateFull;
template.ClientName = clientName;
template.Date = DateTime.Now;
return template;
}
}
public class PartialReport : IReport
{
public TemplateBody GetTemplate(string clientName)
{
TemplateBody template = new TemplateBody();
template.TemplateType = TemplateType.TemplatePartial;
template.ClientName = clientName;
template.Date = DateTime.Now;
return template;
}
}
No comments:
Post a Comment
Please do not enter any HTML. JavaScript or spam link in the comment box.