SOLID – Java2Blog https://java2blog.com A blog on Java, Python and C++ programming languages Tue, 26 Jan 2021 14:35:13 +0000 en-US hourly 1 https://wordpress.org/?v=6.2.9 https://java2blog.com/wp-content/webpc-passthru.php?src=https://java2blog.com/wp-content/uploads/2022/09/cropped-ICON_LOGO_TRANSPARENT-32x32.png&nocache=1 SOLID – Java2Blog https://java2blog.com 32 32 Interface Segregation Principle in java https://java2blog.com/interface-segregation-principle-java/?utm_source=rss&utm_medium=rss&utm_campaign=interface-segregation-principle-java https://java2blog.com/interface-segregation-principle-java/#comments Tue, 02 Jan 2018 18:19:35 +0000 https://java2blog.com/?p=5062 In this tutorial, we will learn about Interface Segregation Principle.It is one of the SOLID principles.
In simple term, Interface Segregation Principle dictates that client should not be forced to implement the methods which it won’t be able to use.You can always throw UnsupportedOperationException from the method which you don’t want to use but it is not recommended and it makes your class tough to use.

Let’s understand with the help of a simple example.
Assume we have created simple Set interface as below.

public interface Set {
   boolean add(E e);
   boolean contains(Object o);
   E ceiling(E e);
   E floor(E e);
}

Create a class TreeSet.java as below.

package org.arpit.java2blog;

public class TreeSet implements Set{

    @Override
    public boolean add(Object e) {
        // Implement this method
        return false;
    }

    @Override
    public boolean contains(Object o) {
        // Implement this method
        return false;
    }

    @Override
    public Object ceiling(Object e) {
        // Implement this method
        return null;
    }

    @Override
    public Object floor(Object e) {
        // Implement this method
        return null;
    }
}

Create another class HashSet.java as below.

package org.arpit.java2blog;

public class HashSet implements Set{

    @Override
    public boolean add(Object e) {
        return false;
    }

    @Override
    public boolean contains(Object o) {
        return false;
    }

    @Override
    public Object ceiling(Object e) {
        // This method is not applicable for HashSet
        return null;
    }

    @Override
    public Object floor(Object e) {
        // This method is not applicable for HashSet
        return null;
    }

}

Do you see the problem, even though you do not require ceiling and floor method in HashSet, we have to implement them.
The correct solution for above problem will be:
Create another interface called NavigableSet which will have ceiling and floor method.

public interface NavigableSet<E> {
   E ceiling(E e);
   E floor(E e);
}

and Set interface will be changed as below

public interface Set {
   boolean add(E e);
   boolean contains(Object o);  
}

Now TreeSet.java will be going to implement two interfaces Set and NavigableSet. Change TreeSet.java as below.

package org.arpit.java2blog;
public class TreeSet implements Set,NaviagableSet{

    @Override
    public boolean add(Object e) {
        // Implement this method
        return false;
    }

    @Override
    public boolean contains(Object o) {
        // Implement this method
        return false;
    }

    @Override
    public Object ceiling(Object e) {
        // Implement this method
        return null;
    }

    @Override
    public Object floor(Object e) {
        // Implement this method
        return null;
    }
}

HashSet will be going to implement only Set as it does not require ceiling and floor methods.

package org.arpit.java2blog;

public class HashSet implements Set{

    @Override
    public boolean add(Object e) {
        return false;
    }

    @Override
    public boolean contains(Object o) {
        return false;
    }

}

As you can see here, HashSet does not implement any method which it does not require.
That’s all about Interface Segregation Principle in java

]]>
https://java2blog.com/interface-segregation-principle-java/feed/ 1
Open Closed Principle in Java https://java2blog.com/open-closed-principle-java/?utm_source=rss&utm_medium=rss&utm_campaign=open-closed-principle-java https://java2blog.com/open-closed-principle-java/#respond Tue, 02 Jan 2018 03:34:03 +0000 https://java2blog.com/?p=5053 In this tutorial, we will learn about Open Closed Design Principle in Java.Open closed principle is one of the SOLID principles.

Open Closed Design Principle dictates that “software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”. This definition was provided by Bertrand Meyer.

Once we have written the class and tested it, it should not be modified again and again but it should open for extension.If we modify already test clasess, it may lead to lot of extras effort to test it back and also there can be chances for the introduction of new bugs.

Strategy Design Pattern is another example of Open Closed design Principle. Service class can use various strategies to perform certain tasks based on requirement so we will keep Service class closed but same time, System is open for extension, by introducing new Strategy which will implement Strategy interface. At runtime, you can call Service Class with any new Strategy, based upon your need.

Let’s understand with the help of a simple example.
You need to create two types(CSV and XML) of reports based on input type.Please note that there should be provision to add new report type in future.

Create an Enum called "ReportType.java" as below.

package org.arpit.java2blog;
public enum ReportingType {
    CSV,XML;
}

Create Service class named ReportingService as below:

package org.arpit.java2blog;

public class ReportingService {

    public void generateReportBasedOnType(ReportingType reportingType)
    {
        System.out.println("===================================");
        System.out.println("Generating report based on Type");
        System.out.println("===================================");

        if("CSV".equalsIgnoreCase(reportingType.toString()))
        {
            generateCSVReport();
        }
        else if("XML".equalsIgnoreCase(reportingType.toString()))
        {
            generateXMLReport();
        }
    }

    private void generateCSVReport()
    {
        System.out.println("Generate CSV Report");
    }

    private void generateXMLReport()
    {
        System.out.println("Generate XML Report");
    }
}

Create a main class named "GenerateReportMain.java" which will called ReportingService to generate report.

package org.arpit.java2blog;

public class GenerateReportMain {

    public static void main(String[] args) {
        ReportingService rs=new ReportingService();

        // Generate CSV file
        rs.generateReportBasedOnType(ReportingType.CSV);

        System.out.println();

        // Generate XML file
        rs.generateReportBasedOnType(ReportingType.XML);

    }

}

Output:

===================================
Generating report based on Type
===================================
Generate CSV Report

===================================
Generating report based on Type
===================================
Generate XML Report

As you can see, this is simple code which is working fine.You have tested code and found out that you are able to generate report based on the type.
Now you need to create one more report type i.e. Excel.If you notice, if you need to make changes as below:
1) You need to make changes in Enum ReportingType.

package org.arpit.java2blog;
public enum ReportingType {
    CSV,XML,EXCEL;
}

2) You need to make changes in ReportingService class which you have already tested.

package org.arpit.java2blog;

public class ReportingService {

    public void generateReportBasedOnType(ReportingType reportingType)
    {
        System.out.println("===================================");
        System.out.println("Generating report based on Type");
        System.out.println("===================================");

        if("CSV".equalsIgnoreCase(reportingType.toString()))
        {
            generateCSVReport();
        }
        else if("XML".equalsIgnoreCase(reportingType.toString()))
        {
            generateXMLReport();
        }
        else if("Excel".equalsIgnoreCase(reportingType.toString()))
        {
            generateExcelReport();
        }
    }

    private void generateCSVReport()
    {
        System.out.println("Generate CSV Report");
    }

    private void generateXMLReport()
    {
        System.out.println("Generate XML Report");
    }

    private void generateExcelReport() {
        System.out.println("Generate Excel Report");
    }
}

Now you can generate Excel reports as below.

package org.arpit.java2blog;

public class GenerateReportMain {

    public static void main(String[] args) {
        ReportingService rs=new ReportingService();

        // Generate CSV file
        rs.generateReportBasedOnType(ReportingType.CSV);

        System.out.println();

        // Generate XML file
        rs.generateReportBasedOnType(ReportingType.XML);

        System.out.println();

        // Generate Excel file
        rs.generateReportBasedOnType(ReportingType.EXCEL);      
    }
}

Output:

===================================
Generating report based on Type
===================================
Generate CSV Report

===================================
Generating report based on Type
===================================
Generate XML Report

===================================
Generating report based on Type
===================================
Generate Excel Report

As you can see, we have to modify at many places which we have already tested and we need to retest all the functionalities again.

Open Closed Design Principle

Let’s see how open closed design principle will be able to solve the problem.
Create ReportingService.java as below.

package org.arpit.java2blog;

public class ReportingService {

    public void generateReportBasedOnStrategy(ReportingStrategy reportingStrategy)
    {
        System.out.println("===================================");
        System.out.println("Generating report based on Strategy");
        System.out.println("===================================");

        reportingStrategy.generateReport();
        System.out.println();
    }
}

Create an interface called ReportingStrategy as below.

package org.arpit.java2blog;

public interface ReportingStrategy {
     void generateReport();
}

Create a class named "CSVReportingStrategy.java" for generating CSV reports

package org.arpit.java2blog;

public class CSVReportingStrategy implements ReportingStrategy {

    @Override
    public void generateReport() {
        System.out.println("Generate CSV Report");
    }
}

Create a class named "XMLReportingStrategy.java" for generating XML reports

package org.arpit.java2blog;

public class XMLReportingStrategy implements ReportingStrategy {

    @Override
    public void generateReport() {
        System.out.println("Generate XML Report");
    }
}

Let’s create a main class GenerateReportMain.java now.

package org.arpit.java2blog;

public class GenerateReportMain {

    public static void main(String[] args) {
        ReportingService rs=new ReportingService();

        //Generate CSV report
        ReportingStrategy csvReportingStrategy=new CSVReportingStrategy();
        rs.generateReportBasedOnStrategy(csvReportingStrategy);

        //Generate XML report
        ReportingStrategy xmlReportingStrategy=new XMLReportingStrategy();
        rs.generateReportBasedOnStrategy(xmlReportingStrategy);
    }
}

Output:

===================================
Generating report based on Type
===================================
Generate CSV Report

===================================
Generating report based on Type
===================================
Generate XML Report

Let’s say you want to generate Excel reports.You need to create below changes:
Create another class named "ExcelReportingStrategy.java" as below.

package org.arpit.java2blog;

public class ExcelReportingStrategy implements ReportingStrategy {

    @Override
    public void generateReport() {
        System.out.println("Generate Excel Report");
    }
}

Change in GenerateReportMain.java to add calling code.

package org.arpit.java2blog;

public class GenerateReportMain {

    public static void main(String[] args) {
        ReportingService rs=new ReportingService();

        //Generate CSV report
        ReportingStrategy csvReportingStrategy=new CSVReportingStrategy();
        rs.generateReportBasedOnStrategy(csvReportingStrategy);

        //Generate XML report
        ReportingStrategy xmlReportingStrategy=new XMLReportingStrategy();
        rs.generateReportBasedOnStrategy(xmlReportingStrategy);

        //Generate Excel report
        ReportingStrategy ExcelReportingStrategy=new ExcelReportingStrategy();
        rs.generateReportBasedOnStrategy(ExcelReportingStrategy);

    }
}

Output:

===================================
Generating report based on Strategy
===================================
Generate CSV Report

===================================
Generating report based on Strategy
===================================
Generate XML Report

===================================
Generating report based on Strategy
===================================
Generate Excel Report

As you can see, we did not make any changes ReportingService which was already tested.We just added new class "ExcelReportingStrategy" which enabled us to generate Excel report.

That’s all about Open Closed Design Principle in Java.

]]>
https://java2blog.com/open-closed-principle-java/feed/ 0
Single Responsibility Principle in Java https://java2blog.com/single-responsibility-principle-java/?utm_source=rss&utm_medium=rss&utm_campaign=single-responsibility-principle-java https://java2blog.com/single-responsibility-principle-java/#comments Thu, 28 Dec 2017 04:30:57 +0000 https://java2blog.com/?p=5044 In this tutorial, we will learn about single responsibility principle in java.It is one of SOLID principles and simplest design principle as well.

Single responsibility principle dictates that there should be only one reason to change the class.If you have more than one reason to change the class then refactor the class into multiple classes according to functionality.

We will understand with the help of a simple example.Let’s say you have  Customer class as below.

package org.arpit.java2blog;

import java.util.List;

public class Customer {

    String name;
    int age;
    long bill;
    List<Item> listsOfItems;

    Customer(String name,int age)
    {
        this.name=name;
        this.age=age;
    }

    // Calculate bill should not be responsibility of customer
    public long calculateBill(long tax)
    {
        for (Item item:listsOfItems) {
            bill+=item.getPrice();
        }
        bill+=tax;
                this.setBill(bill);
        return bill;
    }

    //Report generation should not be responsibility of customer
    public void generateReport(String reportType)
    {
        if(reportType.equalsIgnoreCase("CSV"))
        {
            System.out.println("Generate CSV report");
        }
        if(reportType.equalsIgnoreCase("XML"))
        {
            System.out.println("Generate XML report");
        }

    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public long getBill() {
        return bill;
    }

    public void setBill(long bill) {
        this.bill = bill;
    }

    public List<Item> getListsOfItems() {
        return listsOfItems;
    }

    public void setListsOfItems(List<Item> listsOfItems) {
        this.listsOfItems = listsOfItems;
    }

}

Do you see the problem with the above class? Let’ see what can be the issue with above class.

  • If there is any change in the calculation of bill then we need to change Customer class.
  • If you want to add one more report type to generate, then we need to change Customer class.

If you notice, calculation of bill and report generation should not be the responsibility of Customer, we should create different classes for these functionalities.

Let’s see refactored class now.

package org.arpit.java2blog;

import java.util.List;

public class Customer {

    String name;
    int age;
    long bill;
    List listsOfItems;

    Customer(String name,int age)
    {
        this.name=name;
        this.age=age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public long getBill() {
        return bill;
    }

    public void setBill(long bill) {
        this.bill = bill;
    }

    public List getListsOfItems() {
        return listsOfItems;
    }

    public void setListsOfItems(List listsOfItems) {
        this.listsOfItems = listsOfItems;
    }   
}

Create a new class named BillCalculator and pass Customer object to it.This class will be responsible for calculation of the customer bill

package org.arpit.java2blog;

import java.util.List;

public class BillCalculator {

        public long calculateBill(Customer customer,long tax)
        {
            long bill=0;
            List listsOfItems=customer.getListsOfItems();
            for (Item item:listsOfItems) {
                bill+=item.getPrice();
            }
            bill+=tax;
            customer.setBill(bill);
            return bill;
        }
}

Create a new class named ReportGenerator and pass Customer object to it.This class will be responsible for generation of the customer report

package org.arpit.java2blog;

public class ReportGenerator {

        public void generateReport(Customer customer,String reportType)
        {
            // Extract data from customer object and generate the report
            if(reportType.equalsIgnoreCase("CSV"))
            {
                System.out.println("Generate CSV report");
            }
            if(reportType.equalsIgnoreCase("XML"))
            {
                System.out.println("Generate XML report");
            }

        }
}

As you can see now if we need to change anything in bill calculation, we don’t need to modify customer class, we will make changes in BillCalculator class.
Similarly, If you want to add another reporting type, then you need to make changes in ReportGenerator class rather than Customer class.

That’s all about Single Responsibility Principle in java.

]]>
https://java2blog.com/single-responsibility-principle-java/feed/ 2
SOLID Principles in Java https://java2blog.com/solid-principles-java/?utm_source=rss&utm_medium=rss&utm_campaign=solid-principles-java https://java2blog.com/solid-principles-java/#comments Thu, 09 Nov 2017 14:17:00 +0000 https://www.java2blog.com/?p=4517 In this post, we will see 5 SOLID Principles in Java.

Robert C. Martin gave five objected oriented design principles, and the acronym S.O.L.I.D is used for it. Each letter of this acronym talks about principles in Java. When you use all the principles of S.O.L.I.D in a combined manner, it becomes easier for you to develop software that can be managed easily. The other features of using S.O.L.I.D are:

  • It avoids code smells
  • Quickly refractor code
  • Can do adaptive or agile software development

When you use the principle of S.O.L.I.D in your coding, you start writing the code that is both efficient and effective.

What is the meaning of S.O.L.I.D?

As stated above, S.O.L.I.D represents five principles of Java which are:

  1. S: Single responsibility principle
  2. O: Open-closed principle
  3. L: Liskov substitution principle
  4. I: Interface segregation principle
  5. D: Dependency inversion principle

The article discusses each of this principle in-depth. We will start by considering the very first principle, which is single responsibility principle.

Single Responsibility Principle (SRP)

According to the single responsibility principle, there should be only one reason due to which a class has to be changed. It means that a class should have one task to do. This principle is often termed as subjective.

The principle can be well understood with an example. Imagine there is a class that performs the following operations.

  • connected to a database
  • read some data from database tables
  • finally, write it to a file.

Have you imagined the scenario? Here the class has multiple reasons to change, and few of them are the modification of file output, new database adoption. When we are talking about single principle responsibility, we would say, there are too many reasons for the class to change; hence, it doesn’t fit properly in the single responsibility principle.

Open Closed Principle

According to open closed principle, entities or objects should remain open for extension, but they should stay closed for modification. To be precise, according to this principle, a class should be written in such a manner that it performs its job flawlessly without the assumption that people in the future will simply come and change it. Hence, the class should remain closed for modification, but it should have the option to get extended. Ways of extending the class include:

  • Inheriting from the class
  • Overwriting the required behaviors from the class
  • Extending certain behaviors of the class

An excellent example of an open-closed principle can be understood with the help of browsers. Do you remember installing extensions in your chrome browser?

The primary function of chrome browser is to surf different sites. Do you want to check grammar when you are writing an email using chrome browser? If yes, you can simply use Grammarly extension, it provides you grammar check on the content.

This mechanism where you are adding things for increasing the functionality of the browser is an extension. Hence, the browser is a perfect example of functionality that is open for extension but is closed for modification. In simple words, you can enhance the functionality by adding/installing plugins on your browser, but cannot build anything new.

Let’s take another example.
You are using any Spring function functionality. You can obviously not change the core logic of it, but you can extend Spring framework classes and create your own one.

Liskov Substitution Principle

Liskov substitution principle assumes q(x) to be a property, provable about entities of x which belongs to type T. Now, according to this principle, the q (y) should be now provable for objects y that belongs to type S, and the S is actually a subtype of T. Are you now confused and don’t know what Liskov substitution principle actually mean? The definition of it might be a bit complex, but in fact, it is quite easy. The only thing is that every subclass or derived class should be substitutable for their parent or base class.

You can say that it is a unique object-oriented principle. The principle can further be simplified by understanding this principle; a child type of a particular parent type without making any complication or blowing things up should have the ability to stand in for that parent.This principle is closely related to the Liskov Substitution principle.

Interface Segregation Principle

According to interface segregation principle, a client, no matter what should never be forced to implement an interface that it does not use or the client should never be obliged to depend on any method, which is not used by them.

So basically, the interface segregation principles as you prefer the interfaces, which are small but client specific instead of the monolithic and bigger interface.

In short, it would be bad for you to force the client to depend on a certain thing, which they don’t need.

Let us now again take an example to understand this.

Let’s take a simple example. You are implementing your own ArrayList and LinkedList in java. You create an interface called List which both classes will implement.

package org.arpit.java2blog;

public interface List<T> {
    public T get();
    public void add(T t);
    public T poll();
    public T peek();    
}

Let’s create LinkedList class now.

package org.arpit.java2blog;

public class LinkedList implements List<Integer>{

    @Override
    public Integer get() {
        // Implement this method
        return null;
    }

    @Override
    public void add(Integer t) {
        // Implement this method
    }

    @Override
    public Integer poll() {
        // Implement this method
        return null;
    }

    @Override
    public Integer peek() {
        // Implement this method
        return null;
    }
}

Let’s create ArrayList class now.

package org.arpit.java2blog;

public class ArrayList implements List<Integer>{

    @Override
    public Integer get() {
        // Implement this method
        return null;
    }

    @Override
    public void add(Integer t) {
        // Implement this method
    }

    @Override
    public Integer poll() {
        // ArrayList does not require this method
        return null;
    }

    @Override
    public Integer peek() {
        // ArrayList does not require this method
        return null;
    }
}

Do you see the problem, even though you do not require poll()and peek() methods in ArrayList, we have implemented them.
The correct solution for above problem will be:
Create another interface called Deque which will have peek() and poll() methods.

package org.arpit.java2blog;

public interface Deque<T> {
    public T poll();
    public T peek();    
}

And remove peek and poll from list interface.

package org.arpit.java2blog;

public interface List<T> {
    public T get();
    public void add(T t);   
}

Let’s change LinkedList class now.

package org.arpit.java2blog;

public class LinkedList implements List<Integer>,Deque<Integer>{

    @Override
    public Integer get() {
        // Implement this method
        return null;
    }

    @Override
    public void add(Integer t) {
        // Implement this method
    }

    @Override
    public Integer poll() {
        // Implement this method
        return null;
    }

    @Override
    public Integer peek() {
        // Implement this method
        return null;
    }
}

Let’s change ArrayList class now.

package org.arpit.java2blog;

public class ArrayList implements List<Integer>{

    @Override
    public Integer get() {
        // Implement this method
        return null;
    }

    @Override
    public void add(Integer t) {
        // Implement this method
    }
}

As you can see, we have seggregated two interface to achieve required functionality.

Dependency Inversion Principle

According to this, dependency inversion principle, entities should depend only on abstractions but not on concretions. According to it, the high-level module must never rely on any low-level module but should depend on abstractions. Let us again understand it through another practical example.

You go to a local store to buy something, and you decide to pay for it by using your debit card. So, when you give your card to the clerk for making the payment, the clerk doesn’t bother to check what kind of card you have given. Even if you have given a Visa card, he will not put out a Visa machine for swiping your card. The type of credit card or debit card that you have for paying does not even matter; they will simply swipe it. So, in this example, you can see that both you and the clerk are dependent on the credit card abstraction, and you are not worried about the specifics of the card. This is what a dependency inversion principle is.

Wrap Up

I hope that now you know the basic definition of all the five components of S.O.L.I.D, which are single responsibility principle, open, closed principle, Liskov substitution principle, interface segregation principle, and dependency inversion. So, basically, whenever you write code, you have to keep these core principles in your mind, and actually, to be honest, you have to take these principles as your base map while writing those codes to make it efficient and effective.

The management of the code written by using these principles is also an easy task to do. Using this principle initially in your coding might look odd, but you need to practice writing your codes using these principles, and gradually it will become a part of you. And then, the code that you have written can be easily modified, extended, refactored, or tested without facing any problem according to the requirement that you meet. So practice this principle whenever possible to make your coding better.

]]>
https://java2blog.com/solid-principles-java/feed/ 1