Overview
This article is the first one of the series Spring Framework Fundamentals.
In this very first article, we will explain Object Oriented Programming and some basic principles both with definitions and code samples.
Object Oriented Programming
One of the popular programming paradigms is called Object Oriented Programming, generally abbreviated as OOP, suggests that objects should be used in computer programs.
Objects are special structures in programming contain data in forms of their properties, also named as attributes.
Besides, they contain procedures that are responsible for altering this data which are mostly called as functions.
Hopefully, Java is a clean implementation of the object oriented programming and contains many high-level structures for developers which are formed by objects. Thus we do not need to worry about most of the low-level operations.
However, there are further principles to learn to apply OOP correctly. These are widely known as solid principles in the programming world. When we say solid, this is because they literally form the SOLID. It is a funny story about that our former computer scientists culminated with an acronym for five OOP design principles intended to make software designs better and understandable.
What are these SOLID principles?
We have five principles each of them stands for each letter S-O-L-I-D. They are Single Responsibility Principle, Open Closed Principle, Liskov Substitution Principle, Interface Segregation Principle and Dependency Inversion Principle.
Single Responsibility Principle
Single Responsibility Principle in software programming suggests that an object should only have single responsibility. We usually refer any module, class or function here. In this way, one object can only modify one part of the software’s specifications.
Objects trying to handle more than one responsibility will eventually ensue fragility and become impossible to maintain. Thus, it is highly possible, the violation of this principle causes us the famous God Object anti-pattern in time.
An example to indicate a violation of the single responsibility principle:
LoginManager.java
So this code seems to start smelling like becoming a god object. Although it looks like a semi-god for now, it definitely intends to become bigger in time unless we do not stop it by refactoring:
LoginManager.java
You can check the source code for this sample over here.
Besides, you can read single responsibility principle over on Wikipedia for further details.
Open Closed Principle
Open Closed Principle in software programming means that an ideal software application should be open for extensions but closed for modifications. Doing modification here is thought for changing the existing codes of pre-made modules, classes, etc.
On the other hand, what is mentioned when we say extension is; adding new classes, modules or even functions without touching the rest of the codebase.
Some implications of modification:
- Increases fragility, decreases maintainability.
- Causes strictly tight modules and classes.
- Hard to test, leads to unexpected bugs.
A clear example to show a piece of code which will probably need modifications later:
ModificationManager.java
One proper solution to this problem is Chain of Responsibility pattern which is also a good example of design by extensions, can be achieved like the code below:
ModificationManager.java
You can check the source code for this sample over here.
How the OCP can be used in Java?
One of the best practices is programming to interface when it comes to applying OCP into java. Programming to interface means to prefer using interfaces instead of concrete types unless you specifically need to.
Interfaces are the contracts to expose the behavior type of our program to the outer world. With the help of well-defined interfaces, you always have a chance to create new implementations and easily extend your project without affecting the world outside. This technically means adding an extension.
Hence, we can say that interfaces really play nice with the OCP.
A simple example to show an advantage of using interfaces over concrete types:
CoffeeMachine.java
Besides, you can read open closed principle over on Wikipedia for further details.
Liskov Substitution Principle
Liskov Substitution Principle suggests that objects in a software program should be replaceable with the instances of their subtypes without need to change properties of theirs.
Another use case of interfaces transpires here, since we need a behavioral similarity between subtypes, also called as strong behavioral subtyping. Different behaviors can output different results so we need to group subtypes with similar behavior by using interfaces not to break our program’s communication with the outside.
An example to demonstrate this problem:
An elegant solution comes with the help of interfaces to discriminate subtypes according to their behaviors:
You can check the source code for this sample over here.
Besides, you can read liskov substitution principle over on Wikipedia for further details.
Interface Segregation Principle
Interface Segregation Principle in software simply tells us that instead of one general-purpose interface, it is better to use many client-specific ones. One obvious problem we can encounter when we violate this principle, is the boilerplate invasion of meaningless, empty methods.
Let us show this problem with an example:
And the solution would be splitting our general interface into more specific ones:
You can check the source code for this sample over here.
Besides, you can read interface segregation principle over on Wikipedia for further details.
Dependency Inversion Principle
Dependency Inversion Principle states that in a software program high-level objects should not depend on low-level objects, on the contrary, both should depend on abstractions.
Similarly, concrete classes should depend on abstractions, but abstract ones should not. After these explanations, let’s be a little bit more explanatory.
An example of a DIP violation:
Instead of depending on concrete classes we should definitely make an abstraction by the help of interfaces and refactor our tiny operating system to accept only abstract services in order to initiate on the os startup.
See the code below:
You can check the source code for this sample over here.
Besides, you can read dependency inversion principle over on Wikipedia for further details.
Conclusion
After we explained OOP and the solid principles shortly we will go on Containers, Inversion of Control and Dependency Injection and give some examples about how they are applied in our next article.