Thinking in OOPS
Object Oriented Programming is one of the most misunderstood concepts in today’s world.
It may seem difficult to accept the truth especially when every other programmer is using object oriented language to structure their code.
But do you really understand OOPS and the way it must be used to solve our problems better.
In this article, I have talked about the topic of Object Oriented Programming. What it actually is, its fundamental concept andhow to use it for a good design.
Stay with me for the next 5 minutes and it willhelp you to improve your understanding.
What is OOPS?
Do you know the full form of OOPS?
I mean OOP is very clear and it stands for Object Oriented Programming but what about ‘S’ in OOPS.
If you do not know then it’s fine because it is one of the most confused topics in OOPS.
Some say OOPS stands for Object Oriented Programming Structure, for some ‘S’ stands for System and they try to prove their point by saying that there is a famous conference named as Object Oriented Programming Conference and Structure and some say that ‘S’ doesn’t carry any meaning (bullshit).
I think it’s all nonsense to argue on the meaning of ‘S’.
I think OOP is more of a paradigm than a system.
A paradigm which enables us to think in a proper way, a paradigm that gives us the power to better understand real-world problems and model them through programming.
OOP is a paradigm which is organised around Objects rather than Actions, Data and logic.
Programming has evolved a lot in these past years.
If you compare:
Programming has been more of a logical procedure that takes input as data and performs the logical operation on it to obtain the desired result.
OOP enables you to create a modular design for your application.
Fundamental Concept Of OOP
Abstraction is one of the most fundamental concepts of oop.
It is also a very powerful concept. It helps to solve complex problems.
Abstraction is a concept of dealing with ideas rather than events It is a way to combine smaller things to make a bigger thing.
Suppose, you want to buy a car. You will go to the showroom and look for the complete car, though it is made of many different small modules that are responsible for their own specific task which when work in cohesion creates a single complex entity, which is in our case a CAR.
You will never get to know about the complexity beneath it. That is what abstraction is – Hiding the underlying complexity of the system from the User.
A process of taking away or removing characteristics from something in order to reduce it to a set of essential characteristics.
You will only worry about the looks, feel and superficial specification of the car. You will never ask the sales person to open up the engine to see how it works
Interfaces are a way to achieve Abstraction.
Encapsulation is another fundamental concept of OOP.
This is again one of the most misunderstood concepts in “oop” because different people interpret it differently and that creates confusion.
You may know encapsulation as the hiding of data members and member functions which would simply mean hiding the internal representation of an object from the view outside of the Object’s definition.
Well, it’s not wrong to say that but it is a partial definition.
Encapsulation can be used to achieve data hiding but encapsulation itself is not data hiding.
In fact, In some OOP languages hiding of components is not automatic or can be overridden; thus, information hiding is defined by yet another notion.
There are two parts to encapsulation which is used to distinguish two distinct notions-
- A language mechanism for restricting direct access to some of the object‘s components.
- A language construct that facilitates the bundling of data with the methods (or other functions) operating on that data.
The feature of Encapsulation is often supported by the use of classes, although there are different ways to achieve that.
Third pillar or should I say mechanism to achieve OOP is Inheritance.
Every programmer is familiar with the concept of inheritance.
It provides code re-usability and power to create relationships between multiple objects
It is also used to extend the functionality of a class without changing the actual code of that class. This satisfies the Open/Closed principle of SOLID Design.
But often the concept of inheritance is misused.
Here’s the deal:
If you are using Inheritance only to import the functionality of a class into another then you are doing it wrong. By doing so, you are putting a lot of functionality on the base class.
This results in the creation of a GOD Object.
The real use of inheritance comes when you need to show a relation between any two entities (classic example would be Dog extends Animal). A parent class will not contain anything that would not make sense for its children.
For example – A bark() function would make sense for Dog but it will not make sense for a Fish.
You see, Inheritance is a very good feature of an OOP language. It gives us a way to model real world relations into code. Do not use it for wrong design or convenience.
Always prefer Composition over Inheritance if you need the functionality of the class. Only use inheritance if there is a real relation between the Parent and the Child.
A Good Design
OOP is one of the most used concepts in today’s era.
I would not be 100% correct if I categorize it into a Right or Wrong Design. Because there is not right or wrong.
a good and a bad makes more sense.
Many developers and programmers who have been working in this field has tonnes of experience and has created their own theories and postulates which differentiate one design from another and motivates ones to use a certain design over the other.
Am I making sense?
Are you still with me?
What I’m trying to say here is that if you do not know what’s best, it is better to refer the design patterns which are known to have worked for many different organisations many times. Choose a design pattern that has been tested and the one that is working.
This will give you extra confidence in its implementation because it is already tested by large organisations.
You will also get to know about the pros and cons of using that particular design which will help you better analyse it.
If you are going to formulate your own design, then you must make sure you follow and obey the SOLID Design principles.
This will make your code clean, more independent, more maintainable and you will avoid smelly code.
These principles may sound tough in the beginning but are very easy to grasp.
- S – Single-responsiblity principle
- O – Open-closed principle
- L – Liskov substitution principle
- I – Interface segregation principle
- D – Dependency Inversion Principle
Let’s take each principle one-by-one,
Single Responsibility Principle, in short, is S.R.P
A class should have one and only one reason to change, meaning that a class should have only one job.
Open Close Principle in short O.C.P,
Objects or entities should be open for extension, but closed for modification.
Liskov Substitution Principle in short L.S.P
Derived classes must be useful through the base class interface, without the need for the user to know the difference.
Interface Segregation Principle
The Interface Segregation Principle states that clients should not be forced to implement interfaces they don’t use. Instead of one fat interface, multiple small interfaces are preferred based on groups of methods, each one serving one sub-module.
Don’t be afraid to create multiple interfaces to sub-divide your module.
Dependency Inversion Principle
Check this document out: The Dependency Inversion Principle.
It basically says:
- High-level modules should not depend on low-level modules. Both should depend on abstractions.
- Abstractions should never depend on upon details. Details should depend on abstractions.
DIP reduces the coupling between two pieces of code.
This can be achieved only when you are more dependent on the concept rather than the implementation part of it.
Because you know that changes are risky.
It can really complicate or break your architecture in future.
Therefore, you must write your code in such a way which is time stable. Make your implementation depend on the interface. Dependency Inversion Principle can be achieved this way.
If your implementation depends on the interface then you get the power to choose which implementation is best at runtime and use that instead.
To provide a summary, the Dependency Inversion Principle is primarily about reversing the conventional direction of dependencies from “higher level” components to “lower level” components such that “lower level” components are dependent upon the interfaces owned by the “higher level” components. (Note: “higher level” component here refers to the component requiring external dependencies/services, not necessarily its conceptual position within a layered architecture).
In doing so, a coupling isn’t reduced as much as it is shifted from components that are theoretically less valuable for reuse to components which are theoretically more valuable for reuse.
OOP is one of the most widely used paradigms in today’s world.
The four pillars of OOP i.e, Abstraction, Encapsulation, Inheritance and Polymorphism enables us to write a better code in terms of data rather than logic.
If used properly while implementing SOLID Principles in your design pattern then you not only have created an awesome architecture but you are also saved from writing smelly code.
That’s how powerful OOP is once you conquer it.
I strongly suggest you to read SOLID Design Principles by Uncle Bob which will give you immense insights on the pros and cons of this paradigm and how to avoid the pitfalls.