Brief about Object Oriented Programming and SOLID Principles


Object Oriented Programming - brief Introduction

I trust you already familiar about the concept of Object Oriented Programming, if we talk about the Object Oriented Programming (OOP), it means we are talking about objects or real world entities in the context of programming that the primary aim to bind together the data and the functions. OOP is a programming language model constructed around objects rather than actions and data rather than logic. It enables programmers to build software in manageable pieces rather than in a large amounts of sequential code.

We will not deep dive into details here, though before moving ahead, let us scan briefly the different characteristics of an Object Oriented Programming approach – 

# Objects – Objects are basic and real world run-time entities in an object oriented system, having two characteristics – 
  • Attributes 
  • Behavior
Objects are instances of a class these are defined user defined data types. It takes up space in memory and have associated address like a record in pascal or structure or union in C. 

# Class - Class is a blueprint for the object, like, data and functions or methods. It does not take any space. Class is a user defined data type like structures and unions in C.

# Methods - Methods are functions defined inside the body of a class, used to define the behaviors of an object.

# Inheritance - It refers to the hierarchical arrangement of implementation fragments. Inheritance is a way of creating a new class (derived/child class) for using details of an existing class (base/parent class) without modifying it.

# Encapsulation – It makes the program structure easier to manage because each object’s implementation and state are hidden behind well-defined boundaries. Wrapping up of data and functions into a single unit is known as encapsulation. The data is not accessible to the outside world and only those functions which are wrapped in the class can access it.

# Abstraction – It basically deals with hiding the implementation details and showing the essential things to the outside world. Abstraction helps to reduce complexity, you can achieve the same in two ways - 
  • Abstract Class 
  • Interface

# Polymorphism – It means the ability to take more than one form, an operation may exhibit different behaviors in different instances. Polymorphism means abstract entities are implemented in multiple ways.

SOLID Principles – an Introduction

SOLID is one of the most popular sets of design principles in object oriented programming. It is the coding standard that all developers should have a flawless concept for developing software in a proper way to avoid a bad design.

If you are a developer and build a software without scoping it’s design and forthcoming prospect, the code can become inflexible and more inelastic. It would be more painful to fix small changes and sometime such scenario in the software can result in bugs.  SOLID principle fixes all of these hurdles and make a clear roadmap in the development, it enables developers to create readable and maintainable programs.

SOLID principle is based on five basic principles of object oriented programming that help to build better software architecture, it stands for – 
  1. S – Single Responsibility Principle
  2. O – Open-Closed Principle
  3. L – Liskov Substiution Principle
  4. I – Interface Segregation Principle
  5. D – Dependency Inversion Principle

In fact, the SOLID principles were promoted by Robert C Martin and is used across the object oriented design spectrum. Once you apply the principles, it makes your code more extendable, logical and easier to read. No doubt, it takes some to to recognize, but by using these principles in your code will lead to better quality and well-designed software.


Meanwhile, I am from a Microsoft .NET background, so further in this article will try to walk through the SOLID principles using simple C# examples, though applies to any OOP language. If you see any discrepancy or improvements needed for this articles, feel free to put your comments in the comment box.

SRP – Single Responsibility Principle

In programming, the Single Responsibility Principle(SRP) refers that every module or class should have responsibility over a single part of the functionality. It means every class is responsible for exactly one thing, it has one reason to change. If a class has more than one responsibility, it becomes coupled. Further, a change to one responsibility results in modification of the other responsibility. Henceforth, a class need to server multiple purpose or responsibility, then it should be made into a new class.

Single Responsibility Principle

It's better to see the same using a code scenario, look the below listed code snippet and try to identify the problem.

SRP example

Here you can see that the Employee class is taking care primarily employe insertion, in reference to database connection and adding employee in table etc. Along with this, you can see the Employee class also taking care additional logging activity under catch block. In other words the class is taking two responsibilities in place of core insertion part.

Supposed tomorrow you get an additional task to implement a new logger like event viewer, then you will have to alter Employee class, that was not supposed to do. Because Single Responsibility Principle (SRP) states that a class should have only one responsibility not overloaded with different responsibility. So as per SRP approach we can move the logging activity to some other class that will take care logging activities solely, something like below listed code snippet – 

SRP example

You can see that the logging activities moved on to LogUtility class and can concentrate on Employee class for employee related activities. Now you can apply the LogUtility class in the Employee class as per desired log activities.

SRP Example

I tried to reflect a simple example in reference to the Single Responsibility Principle concept. However, in the context of architecture thought you can think beyond of  this logging approach, like can go for a global error handler by using Global.asax file.

OCP – Open Closed Principle

In a programming paradigm, classes, modules, functions etc. considered as software entities. Here, Open Closed Principle (OCP) states that software entities should be open for extension only, but closed for modification. It means you should be able to extend a class behavior without modifying it, can be achieved by using inheritance. If you create a subclass of the base class, then you just extended rather than any modification in the original class. In brief, the original class is closed now for modification, but you can add required code to your subclass to fulfill new behavior.

Open Closed Principle

Let us consider the same example, employee class where I have added an employee type property to the class. Now Employee type can be any one of the below category – 
  • Probation – In probation employee can have limited facilities and perks.
  • Permanent – Permanent employee can get all facilities as well perks.

OCP Example

Scenarios are in this way, if we need a new employee type (e.g. Contract, Trainee, Intern, etc.) we need to go and add one more IF condition in the GetBonus function. Somehow you are going to change the employee class.

If you are going to alter the employee class again and again, then need to ensure you validated the existing conditions as well new ones. If I talk about an extension rather than updating the existing class, then you can focus in new code regardless to check and test the existing code.

Here, extension says that you are going to create a new class, which will extend the Employee class. In this way we are not going to touch the original class, like the below listed code snippet – 

OCP Example

I created a base class with the GetBonus function, now based on the new employee type required to create new classes and will have to overwrite the GetBonus function accordingly, like – 
OCP Example

In a simple word the Employee class is now closed to any type of modification, but it is open for extensions whenever a new employee type provided.

LCP – Liskov Substitution Principle

I trust it would be a bit tougher one to grasp the approach, if bring together for the first time. In fact, the Liskov Substitution Principle (LCP) was introduced by Barbara Liskov in one of her conference keynote “Data abstraction”. 

In programming, Liskov Substitution Principle states that if S is a sub-type of T, then objects of type T may be replaced with objects of type S. If I consider this formula mathematically, then it would be something like – 

Let ϕ(x) be a property provable about objects x of type T.
Then ϕ(y) should be true for objects y of type S, where S is a subtype of T.

A bit puzzled, let me simplify this – a subclass or derived class should be substitutable for their base class. In a general way it says that object in a program should be replaceable with an instance of their sub-types without making any correctness of that program.

Still some confusion, let me go through the same example the Employee class to make you understand the principle better. See the listed below snapshot, Employee is a base/parent class and Probation, Permanent and Contract Employee are the derived/child classes by using the inheritance feature.

LSV Example

Here you can see I added one more type Contract, since this is a contractual type of job and not on the company pay roll, mostly out-sourced from another company. Now new scenario is to calculate the bonus for contractual employee. 

Still no issues, you can give him bonus as per policy, but can not save under the company’s employee database because they are not actual employee. Henceforth we create a new class named as Contract that inherits from the base class Employee. As talked and as per policy, we provide some bonus, but cannot insert entry into employee database. So we need to override the InsertEmployee method precisely to avoid insertion using an exception indicating that no one can add Contract type of employee to the database.

Once again look the listed below the base class Employee, having two methods as – 
  • GetBonus – Calculate the bonus percentage based on employee type.
  • InsertEmployee – Insert the employee records into employee database.

LSV Example

Now I am going to display the two classes for the Probation and Permanent type of employee, both inherited the hierarchy from the parent class.

LSV Example

Till here, did you notice any odd things, I trust most probably not because both classes inherit from the parent class. Next, observe closely the further child class based on Contract type which we want to provide bonus, but not moving to save the entry in the employee database.

LSV Example

Up to this class definition, everything looks fine based on OOP approach. Now for a scenario I am going to create a list collection of Employee, obviously the approach would be based on Polymorphism approach.

LSV Example

Here you can get the problem, puzzled, look more closely the code snippet. Based on inheritance approach, the Employee object can point to any of its child objects and here we are not expecting any exception. 

Now look  one more snapshot, it was based on execution of the code – 

LSV exception

During foreach loop execution, once InsertEmployee method of the ContractEmployee object is invoked, it leads to an exception. Yes, it should throw exception as we wanted to avoid an entry of Contract employee into employee database, so implemented NotImplementedException accordingly.

Now look the entire scenario again, think twice about the problem. ContractEmployee class throws an exception which in fact should not throw, it is a violation of the Liskov Substitution Principle. In simple words, ContractEmployee has bonus calculation, looks like an employee, but it is an outsourced person based on another company’s payroll. Moral of the story, the parent cannot replace the child object without a glitch. In brief Employee is not the real parent of the ContractEmployee class, it is a different entity with a different approach.

But, Liskov Substitution Principle states that the parent should easily replace the child object. To solve this, essentials to define two different interfaces for bonus calculation as well insure entry into employee database respectively.

LSV Example

Next as a change, the ContractEmployee class will inherit from the IBonus interface as it not fit for the InsertEmployee method, so no need to inherit the IDBExecution.

LSV Example

Here, ContractEmployee class is concerned with bonus part not database execution, that’s why inherited the IBonus interface. However the Employee table will implement both interface as IBonus as well IDBExcution.

LSV Example

I trust, now you have convinced about the LSP approach. In the meanwhile I try to execute the same list code without removing the ContractEmployee class, here you will get a compiler alert about some invalid argument. 

LSV Compile Error

ISP – Interface Segregation Principle 

Once you are coding, you  create classes as well interface, but, it is essential to keep the interface as specific as possible. It is good to have small and precise interfaces, so the client can use the required methods rather than forcing to use all methods which is really not needed for them.

In brief, Interface Segregation Principle (ISP) states that a client should not be forced to implement an interface that it doesn’t use. Make practice, do not add additional functionality to an existing interface by adding new methods. Instead, create a new desired interface and let your class implement multiple interfaces if needed.

Interface Segregation Principle

Let me elaborate this using the same example we have already gone through the IBonus and IDBExecution interface. Just assumed, we have applied this interface more than 100 clients and they are happy to use the IDBExecution interface. IDBExecution interface executes only one method as InsertEmployee and return a boolean acknowledgement true or false.

ISP Example

Now you get a new client and bit modified requirement, need to display employee details along with insertion into a database. I know it is pretty easy and the same you implemented a new interface to show details of employee based on employee id.

ISP Example

Happy about the implementation, wait and thing again, you are breaking the approach. Somehow you are providing solution to new client, but forcing all existing clients to use this new GetEmployeeDetails method simultaneously.

To avoid such awful thing, better to go for a new interface for a new type of necessities. Motto behind this, to keep existing satisfied client happy with their need and focus the new client separately with their desired needs.

ISP Example

In such scenario, you will have to inherit both interfaces if requires insertion as well display employee details. Even this is a good solution, though you can combine the method in one interface by using inheriting the first interface in second interface as listed below code snippet.

ISP Example

Now your approach looks better and justify the Interface Segregation Principle (ISP) that the existing client will continue using the IDBExecution interface. Along with this, the new client who demanded both functionalities will go with IDBGetExecution interface.

ISP Example

Here I continue with the same Employee class to insert employee details into a database, but created a new class using new the interface to utilize bot functionalities the insertion as well get details.

ISP Example

DIP – Dependency Inversion Principle 

Dependency Inversion Principle (DIP) is the last principle in the context of SOLID principles. Using Dependency Inversion Principle, this is a way to decouple software modules rather than writing tightly coupled code that leads to application bigger. 

Dependency Inversion Principle states that – 
  • High level modules should not depend on low level modules, both should depend on abstractions. 
  • Abstractions should not depend on details. Details should depend on abstractions.

In simple words, if a class depends on another class, then essentials to change the one class if something alteration done in the said dependent class. Henceforth it is preferable to go with writing loosely coupled class.

Let me narrate an usual, real life scenario, might be you carrya  Visa credit card. Whenever you do shopping in supermarket, used to pay with this Visa credit card. Cashier used to take your card and swipe in the Visa machine once verified that this is the Visa card. Neither you nor the cashier bother about credit card specifics, since both of you depends on abstraction of credit card.

Let us go through our code,might be you remember we had implemented a logger class to justify the Single Responsibility Principle (SRP). 
DIP Example

Here you can see that you can log the exception in two ways only either file based logging or event viewer. In required to deliver a new approach, then you will have to change logging system. In fact, this is referred as tightly coupled and using loosely coupled you can accomplish the assignment. 

Now we almost completed the different type of SOLID principles, so can go ahead to create a common interface for logging activities. 

DIP Example

Using this new interface, further you can implement a different logging class and achieve the demand of task accordingly. 

DIP Example

Now based on the need, you will have to use specific class to achieve the desired logger. For example, assumed about one scenario where errors will be logged in a file, so will implement the FileUtility class in the module.

Let’s know a little bit about dependency injection, before finishing the Dependency Inversion Principle.

DIP Example

Here in the above code snippet you can use some approach to select the file logger, though that is not an issues. The problem is the Employee class which depends on FileUtility class, look closely the New keyword that states which object will be instantiated.

If we delegate this responsibility for the Employee class to someone, then most probably issues will be resolved. Now, we can implement dependency injection so that it would be converted to loosely coupled. Let us see the Dependency Injection (DI) approach in a brief way, later will continue the DIP logger example and solution.

Dependency Injection 

Wikipedia says – In software engineering, dependency injection is a technique whereby one object (or static method) supplies the dependencies of another object. A dependency is an object that can be used (a service). An injection is the passing of a dependency to a dependent object (a client) that would use it.

Still not easier to understand, lets see the bits and pieces in a general way. Dependency means relying on something for taking care, similarly in programming, when a class uses some functionality of another class, then its said first class has a dependency of the second class.

Dependency Injection

Here you can see Class A and Class B are using some common method from the Class X, then it means Class A and Class B have a dependency of Class X. In Object Oriented Programming, you will have to create the object of that class which method is required to use in your class. For example, Class A or Class B will create an instance of Class X to use X’s method.

If I talk about transferring the task of creating the object to someone else and directly using the dependency is called dependency injection. In fact, Dependency Injection (DI) is a design pattern that removes the dependency from the programming code so that it would be easier to manage and test the application.

Dependency Injection is a way to develop loosely coupled code, enables us to better manage future changes and other complexity in our software. We have the following different ways to implement DI – 
  1. Constructor Injection – Most widely used option, Dependency Injection is done by supplying the dependency through the class’s constructor during creating the instance of that class.
  2. Property/Setter Injection – Ideal place to use when a class has optional dependencies, or where the implementations may require to be swapped. Does not require the creation of a new object or modifying the existing one. Without changing the object state, it could work.
  3. Method Injection – Rarely used option, Inject the dependency into a single method and generally for the use of that method. It could be useful, where the whole class does not need the dependency, only one method having that dependency.

Continue….Dependency Inversion Principle 

In the above DIP example, we had encountered that Employee class is taking responsibility to create an object of FileUtility class using the New keyword. It is a violation of the dependency inversion principle. 

If we delegate this responsibility for the Employee class to someone, then most probably issues will be resolved as we talked till now. Now, you can use dependency injection using Constructor Injection – 

DI Example

Here, we applied the Constructor Injection, passed the ILogUtility interface as an input parameter by injecting dependencies of Employee class in its constructor. By using dependency injection no longer rely on the Employee class to define the precise type of log utility.

Congratulations, we covered the SOLID principles! 😊

Might be you are in a bit puzzled or alarmed mode, don’t worry about the way you are writing your code. SOLID principle will help you to write loosely coupled code which would be highly maintainable and less error oriented. Initially, it can take time to be habitual about these principles, but with steady practice , will become a part of your coding style. The SOLID principles are guidelines that can help you create maintainable and extendable classes and systems.

If you see any discrepancy or have any question regarding this article or anything I should correct or add, please feel free to drop a remark in the below comment box.

Keep visiting Solution Mandi !

No comments:

Post a Comment