Professional Tips: Top 10 Design Principles in Java 2023

In this Article we will cover different design principles in Java for building Robust and Flexible Applications. These design principles need to be followed for saving us from bad design while doing coding.Let’s jump into 10 design principles which should drive the way we code.

Design Principles
Image by rawpixel.com on Freepik

DRY – Don’t Repeat Yourself

This is one of the most basic design principles that needs to be adhered.We should always keep duplication away in our codes.I have mentioned below few simple ways to avoid duplication of code.

  • If you have block of code in more than two place consider making it a separate method.
  • If you use a hard-coded value more than one time make them public final constant.
  • Create Util classes to keep methods used across classes.
  • Use Abstraction to abstract common things in one place

Encapsulate What Changes

Only one thing is constant in software field and that is “Change”, So encapsulate the code you expect or suspect to be changed in future.

Benefit of this Design principle is that Its easy to test and maintain proper encapsulated code. If you are coding in Java then follow principle of making variable and methods private by default and increasing access step by step e.g. from private to protected and not public. Several of design patterns in Java use Encapsulation. Factory Design Pattern is one example of Encapsulation which encapsulate object creation code and provides flexibility to introduce new product later with no impact on existing code.

Favour Composition over Inheritance

Always favor composition over inheritance ,if possible. Composition allows to change behavior of a class at runtime by setting property during runtime and by using Interfaces to compose a class we use polymorphism which provides flexibility of to replace with better implementation any time.

Programming for Interface not implementation

Always program for interface and not for implementation this will lead to flexible code which can work with any new implementation of interface. So use interface type on variables, return types of method or argument type of methods in Java.

Delegation principle

Don’t do all stuff  by yourself,  delegate it to respective class. Classical example of delegation design principle is equals() and hashCode() method in Java.Benefit of this design principle is no duplication of code and pretty easy to modify behavior.

SOLID Design Principles

SOLID design principles serve as fundamental guidelines for writing clean, maintainable, and extensible code. Each principle in SOLID is represented by a letter:

  • Single Responsibility Principle (SRP): A class should be designed to perform a single responsibility.
  • Open/Closed Principle (OCP): Classes, methods or functions should be Open for extension and Closed for modification.
  • Liskov Substitution Principle (LSP): Subtypes should be capable of substituting their base types.
  • Interface Segregation Principle (ISP): Clients should not be burdened with dependencies on interfaces they don’t use.
  • Dependency Inversion Principle (DIP): High-level modules should rely on abstractions, not low-level modules.

Single Responsibility Principle (SRP)

A class should be designed to perform a single responsibility. For example , a Calculator class should have APIs for performing mathematical operations like addition,multiplication etc.It should not handle email functionality.

If you put more than one functionality in one Class,  it introduces coupling between two functionalities and even if you change one functionality there is chance you broke coupled functionality,  which require another round of testing to avoid any surprise on production environment.

Open Closed Design Principle

Classes, methods or functions should be Open for extension (new functionality) and Closed for modification. Adding new functionality should have as minimum impact as possible on the existing code since the existing code is already unit tested and changes in already written code might affect the existing functionality in an unwanted manner.

You should design modules that never change.
When requirements change, you extend the behavior of such modules by adding new code, not by changing old code that already works.

Liskov Substitution Principle (LSP)

Derived types must be completely substitutable for their base types. Likov’s Substitution Principle states that if a program module is using a Base class, then the reference to the Base class can be replaced with a Derived class without affecting the functionality of the program module. We must make sure that the new derived classes just extend without replacing the functionality of old classes. Otherwise the new classes can produce undesired effects when they are used in existing program modules.

Interface Segregation principle (ISP)

The principle states that clients should not be forced to implement interfaces they don’t use. Instead of one fat interface many small interfaces are preferred based on groups of methods, each one serving one submodule.

This happens mostly when one interface contains more than one functionality, and client only need one functionality and not other. Interface design is 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, interface has disadvantage to implement all method before any class can use it so having single functionality means less method to implement.

Dependency Inversion principle

This says that one class should depend upon abstractions not concrete implementations. This helps in building loosely coupled components.

Dependency Injection:

The Dependency Injection pattern is an implementation of Dependency Inversion principle. It says “Don’t ask for dependency it will be provided to you by framework“.

Advantages of Dependency Injection:

  • More Readable Code
  • Loose Coupling
  • More Testable Code
  • More Reusable Code

Conclusion

In conclusion, the top 10 design principles in Java offer essential guidelines for creating robust and maintainable software. By applying these design principles, developers improve code reusability, modularity, and readability. Emphasizing encapsulation, abstraction, and loose coupling enables flexible and adaptable systems. Incorporating these design principles in Java projects helps build resilient and efficient software, meeting the evolving needs of modern applications.

Book Recommendations on Design patterns :

Design patterns book by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, also known as the “Gang of Four” (GoF) Design Patterns: Elements of Reusable Object-Oriented Software

4 comments

  1. Hi Gyan,

    Regarding the DI principle, I found some different definition in some other blogs:
    The one that is mentioned here is Dependency Injection that can be achieved in three ways:
    1. Constructor injection
    2. Method injection
    3. Property injection.
    But according to some other blogs, Dependency Injection is not a design principle, rather Dependency Inversion is the DI of SOLID that states:
    1. High-level modules should not depend on low-level modules. Both should depend on abstractions.
    2. Abstractions should not depend upon details. Details should depend upon abstractions.
    Few blogs are:
    https://www.codeproject.com/Articles/615139/An-Absolute-Beginners-Tutorial-on-Dependency-Inver
    https://www.codeproject.com/Articles/495019/Dependency-Inversion-Principle-and-the-Dependency
    https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)

    Best Regards,
    Vivek

    1. If you see I have written Dependency Injection or Inversion principle. You are right, Dependency Inversion is the principle whereas Dependency Injection is the pattern developed on top of the Dependency Inversion principle.

Leave a Reply

Your email address will not be published. Required fields are marked *