OOP Design Principles
The ‘Object-Oriented Design(OOP) Principles’ are the fundamentals of OOP programming, but from my experience, I have seen most of the Java programmers chasing design patterns like Decorator pattern, or Observer pattern, Singleton pattern and not putting enough efforts on learning Object-oriented analysis and design.
It’s very much important to learn the basics of Object-oriented programming like Encapsulation, Polymorphism, Abstraction, and Inheritance. But, at the same time, it’s equally powerful to know object-oriented design principles.
If you are struggling to understand a design principle, you must try to do more than one example because sometimes we connect to another example or author better but you must understand these design principles and learn how to use it in your code by yourself.
One of the best ways of learning any design principle or pattern is a real-world example and understanding what will be the consequences of violating that design principle, the intention of this article is Introducing Object-oriented design principles for Java Programmers, who are either not aware of it or in the learning phase.
From my point of view, I personally think each of these OOP and SOLID design principles needs an article to explain to them clearly, and I will definitely try to do that here.
1.DRY (Don’t repeat yourself)
DRY is Our first object-oriented design principle. as you can clearly see the name suggests DRY (don’t repeat yourself) means don’t write redundant or duplicate code, instead use Abstraction to abstract common things in one place.
suppose you have a block of code in more than two places you can consider making it a separate method, or if you using a hard-coded value more than one time you can make them public final constant. The benefit of this Object-oriented
It means if you have used common code to validate userName and SSN it doesn’t mean they are the same or they will remain the same in the future.
By using familiar code for two distinct functionality or thing you closely couple them forever and when your userName changes its format, your SSN validation code will break.
So be careful of such coupling and just don’t mix anything which uses similar code but is not related.
2.Encapsulate What Changes
Change is the one and the only thing which is constant in the Information Technology world, So, encapsulate the code that you expect or suspect to be changed in the future.
The advantage of this OOP Design principle is that It’s easily testable and maintain proper encapsulated code.
If you are coding or programming in Java then follow this simple principle of making variable and methods private by default and increasing access step by step like from a private to protected and not public.
There are many design patterns in Java uses Encapsulation, the Factory design pattern is one example of Encapsulation in design patterns which encapsulates or binds object creation code and provides quality to introduce a new product later with no impact on existing code.
3.Open Closed Design Principle
According to one of these Object-Oriented Design principles, “Your Classes, methods or functions should be Open for extension (new behavior) and should Close for modification”.
This is another attractive SOLID design principle, termed by Uncle Bob on his classic Clean Codebook, which prohibits someone from changing code which already tried and tested.
The important benefit of this design principle is that already tried and tested code is not touched which means they won’t break.
Here is a Java code example which breaches the Open-Closed Design Principle of Programming:
In the above code GraphicEditor, the object is tightly coupled with Shape Object, If you need a new Shape then you need to modify already tried and tested code inside the raw shape(Shape s) method, which is both error-prone and not desirable.
Ideally, if you are adding new functionality only than your code should be tested and that’s the goal of the Open Closed Design principle.
4.Single Responsibility Principle (SRP)
Single Responsibility Principle is just another SOLID design principle in OOP, and represent S on the SOLID acronym. What SRP says is that there should not be more than one reason for a class to change, or a class should always handle single functionality.
For instance, If you put more than one functionality in Single Class in Java it introduces coupling between two functionality and even if you change one functionality there is a chance you shatter coupled functionality, which requires just another round of testing to avoid any surprise or revelation on the production environment.
- Dependency Injection or Inversion principle
What this principle says is do not ask for dependency it will be provided to you by the framework. This concept has been very well implemented or provided in the Spring framework, which is one of the most popular Java frameworks for writing applications of real-worth
The importance of this design principle is that any class which is injected by the Dependency Injection framework is easy to test with the duplicate object and easier to maintain because object creation code is centralized in the framework and client code is not messed up with that.
There are multiple methods in which you can implement a Dependency injection feature like using proxies just like used in Spring or using bytecode instrumentation which some AOP (Aspect Oriented Programming) framework like AspectJ does.
Here is an example of the code which breaches Dependency Inversion Principle or we can say DIP in Java:
You can see that EventLogWriter is the dependency of AppManager which is tightly coupled with the AppManager. If you need to use another way to notify your client like by sending push notifications, SMS, or E-mail, you need to change the AppManager class.
By using the Dependency Inversion Principle can solve Such type of problem. where instead of AppManager asking for EventLogWriter, it will be injected or provided to AppManager by the framework like Spring.
6.Favor Composition over Inheritance
Basically, there are two general ways in which we can reuse the code that you have already written, Inheritance and Composition, both have their own advantage and disadvantages, but, in general, you should always use or favor composition over inheritance, if possible.
Some of you may argue this, but according to me and what I found that Composition is the lot more flexible than Inheritance.
Composition allows you to change the behavior of a class at run-time by setting property during run-time and by using Interfaces to compose a class we can make use of polymorphism which supplies better flexibility to replace with better implementation at any time.
- Liskov Substitution Principle (LSP)
According to the Liskov Substitution Principle, Subtypes or subclasses must be substitutable for supertype or Superclass I mean methods or functions which use superclass type must be able to work with the object of subclass without any issue”.
However, LSP is somehow closely related to the Single responsibility principle and Interface Segregation Principle.
If a class has more functionality than the subclass might not support some of the functionality and does violate LSP.
If you want to follow LSP SOLID design principle, derived class, child class or subclass must intensify functionality, but not reduce them. LSP represents “L” on the SOLID acronym.
Here is a code example which breaches the Liskov Substitution Principle in Java:
Liskov Substitution Principle in Java
If you have a method area(Rectangle r) which calculates the area of Rectangle then that code will break when you pass the Square because Square is not really a Rectangle.
- Interface Segregation Principle (ISP)
What Interface Segregation Principle says that a client should not implement an interface if it doesn’t use that or if there is no need of that interface.
This usually happens when one interface consists of more than one functionality, and the client only needs one functionality and no required other functionality.
There is no doubt that Interface design is somehow a tricky job because once you release your interface you can not change it without breaking all implementation. Well, Java 8 version’s default or defender method feature does provide a way for interface evolution but the question is how many Programming languages support those features?
One of the main advantages of this design principle in Java is, the interface has the disadvantage of implementing all methods before any class can use it so having single functionality means there is less method to implement
- Programming for Interface not implementation
A programmer should always focus on writing a program for the interface and not for implementation this will lead to pliable code that can work with any new implementation of the interface.
In simple or concrete words, you should always be using interface type on variables, return types of a method or argument type of methods in Java-like using SuperClass or Parent class type to store object rather than using SubClass.
I mean to use this approach
List numbers= getNumbers();
instead of using this approach
ArrayList numbers = getNumbers();
Don’t do all code by yourself, assign it to the respective class. One Of the common examples of delegation design principle is the equals() and hashCode() method in Java.
If we want to compare two objects for equality, what we do is we ask class itself to do comparison instead of the Client class doing that check.
The important benefit of this design principle is no redundancy of the code and pretty easy to modify behavior.
Shah Rukh Patwekar | Software Trainer
SevenMentor Pvt Ltd.
Call the Trainer and Book your free demo Class for JAVA now!!!
© Copyright 2019 | Sevenmentor Pvt Ltd.