Object-Oriented Design Principles in Java
Object-Oriented Design Principles in Java
Want to learn more about implementing object-oriented design principles in your Java code? Check out this post on OOP to learn more!
Join the DZone community and get the full member experience.Join For Free
In this article, we will learn the object-oriented design principles that can be applied in our day-to-day project work. It's important to learn the basics of object-oriented programming, like abstraction, encapsulation, polymorphism, and inheritance. But, at the same time, it's equally important to know object-oriented design principles, to create a clean and modular design. These guidelines help design strong object-oriented software design.
First, let's list the important object-oriented design principles, and we will discuss each guideline in greater detail.
Encapsulate What Varies
- If you know your code is going to change in future, then separate it out.
- The benefit of this OOP design is that it's easy to test and maintain the proper encapsulated code.
- Only one thing is constant in the software field and that is change. So, encapsulate the code you expect or suspect to be changed in future.
- If you are coding in Java, then follow the principle of making variable and methods private by default and increasing access, e.g. from private to protected and not public. Several of the design patterns in Java use Encapsulation. The factory design pattern is one example of encapsulation, which encapsulates an object creation code and provides flexibility to introduce a new product later with no impact on existing code.
Code to an Interface Rather Than to an Implementation
- Always program for an interface and not for implementation. This will lead to a flexible code that can work with any new implementation of an interface.
- Use the interface type on variables, return types of method or argument type of methods in Java. This has been advised by many Java programmer, including books like Effective Java and Head First design pattern book.
- Don't do all stuff by yourself, delegate it to respective class. A great example of delegation design principle is the
hashCode()method in Java.
- In order to compare two objects for equality, we ask the class itself to do a comparison instead of the Client class doing that check. The benefit of this design principle is no duplication of the code and it is pretty easy to modify behavior.
Read more here in the article Delegation in Java with Examples
Open-Closed Principle (OCP)
- Classes should be open for extension but closed for modification.
- Classes, methods, or functions should be open for extension (new functionality) and closed for modification.
- The benefit of this object-oriented design principle is to prevent programmers from changing already tried and tested code.
Read more here: Open-Closed Principle with Example
Dry —Don't Repeat Yourself
- Avoid duplicate code by abstracting common things and place them in a single location.
- Use an abstract class to abstract common things in one place. If you have a block of code in more than two places, consider making it a separate method, or if you use a hard-coded value more than one time, make them public static final constant.
- The benefit of this object-oriented design principle is in maintenance.
Single Responsibility Principle (SRP)
- Every object in our web application should have a single responsibility, and all object's services should be focused on carrying that single responsibility(SRP).
- If you put more than one functionality in one class in Java, it introduces coupling between two functionalities, and even if you change one functionality, there is a chance you broke coupled functionality, which requires another round of testing to avoid any surprise on the production environment.
Read more here: Single Responsibility Principle with Example
Liskov's Substitution Principle (LSP)
- A subclass should be suitable for their base classes.
- According to the Liskov Substitution Principle, subtypes must be substitutable for supertype, i.e. methods or functions, which use a superclass type to be able to work with the object of a subclass without any issue.
- LSP is closely related to the single responsibility principle and the interface segregation principle. If a class has more functionality than a subclass, it might not support some of the functionality and does violate LSP.
Read more here: Liskov's Substitution Principle with Example
Interface Segregation Principle (ISP)
- Interface Segregation Principle stats that, a client should not implement an interface if it doesn't use that.
- This happens mostly when one interface contains more than one functionality, and the client only needs one functionality and no other. Interface design is a tricky job because once you release your interface you can not change it without breaking all implementation.
- Another benefit of this design principle in Java is, an interface has the disadvantage of implementing all method before any class can use it so having single functionality means less method to implement.
Read more on Interface Segregation Principle with Example
Dependency Injection or Inversion Principle
- Don't ask for a dependency — it will be provided to you by a framework. This has been very well implemented in the Spring framework. The beauty of this design principle is that any class that is injected by the DI framework is easy to test with the mock object and easier to maintain because object creation code is centralized in the framework and client code is not littered with that.
- There are multiple ways to implement a dependency injection, like using bytecode instrumentation, which some AOP (Aspect Oriented programming) frameworks, like AspectJ, do, or by using proxies, just like those used in Spring. See this example of IOC and the DI design pattern to learn more about this SOLID design principle.
Opinions expressed by DZone contributors are their own.