Interface segregation principle in Java

Avatar of Rakesh Mothukuri

Rakesh Mothukuri

| Reading Time : 4 minutes

Avatar of Rakesh Mothukuri Avatar of Rakesh Mothukuri Avatar of Rakesh Mothukuri Avatar of Rakesh Mothukuri

Interface Segregation Principle

Interfaces play an important role in Java programming language and they are widely used for abstraction and to support multiple inheritances.

Interface is achieved by using a keyword interface and declare methods in it. Classes can implement interfaces with the implements keyword, and then provide implementations for the declared methods. One of the design principles to keep in mind while writing interfaces is the Interface Segregation Principle.

In Interface Segregation Principle interface should not have methods that implementing classes don’t require. Implementing classes are for no reason forced to provide implementations for those methods it does not require to. An addition of a method or change to a method signature to interface requires changing all classes implemented in this interface.

The Interface Segregation Principle suggests segregating an interface into smaller and highly cohesive interfaces, known as “role interfaces” and each “role interface” declares one or more methods for specific behavior. Thus clients, instead of implementing an interface implements only those “role interfaces” whose methods are relevant.

Bad Example

Consider the requirements of an application that builds different types of transportation vehicles. Each vehicle will have a price and color. Vehicles such as car can start and stop moving while some vehicles such as airplanes can both move and fly. Example interface

Vehicle.java

public interface Vehicle {
    void setPrice(double price);
    void setColor(String color);
    void start();
    void stop();
    void fly();
}

A class that represents an aeroplane can implement the Vehicle interface and provide implementations of all the interface methods. But, imagine a class that represents a car. This is how the Car class will look.

Car.java

public class Car implements Vehicle {
    double price;
    String color;
    @Override
    public void setPrice(double price) {
        this.price = price;
    }
    @Override
    public void setColor(String color) {
        this.color=color;
    }
    @Override
    public void start(){}
    @Override
    public void stop(){}
    @Override
    public void fly(){}    
}

As you can see in the code, Car needs to provide an implementation fly() method, even though it does not require them. This is a violation of the Interface Segregation Principle. These might affect code readability

Good Example

Following the Interface Segregation Principle, we can address the problem of the vehicle interface, solution is- Segregate the Vehicle interface into multiple role interfaces each for specific behavior. In this case, Vehicle interface can be broken down into three interfaces: Toy, Movable, and Flyable.

Vehicle.java

public interface Vehicle {
     void setPrice(double price);
     void setColor(String color);
}

Movable.java

public interface Movable {
    void start();
    void stop();
}

Flyable.java

public interface Flyable {
    void fly();
}

Now Vehicle interface with the setPrice() and setColor() methods as all vehicles will have a price and color, all Vehicle implementation classes can implement this interface. Then, Movable and Flyable interfaces to represent moving and flying behaviors in vehicles.

Implementation

Car.java

public class Car implements Vehicle, Movable {
    double price;
    String color;

    @Override
    public void setPrice(double price) {

        this.price = price;
    }
    @Override
    public void setColor(String color) {

        this.color=color;
    }
    @Override
    public void start(){
        // Implementation
    }
    @Override
    public void stop(){
        // Implementation
    }
}

Aeroplane.java

public class Aeroplane implements Vehicle, Movable, Flyable {
    double price;
    String color;

    @Override
    public void setPrice(double price) {

        this.price = price;
    }

    @Override
    public void setColor(String color) {
     this.color=color;
    }
    @Override
    public void start(){
        // Implementation
    }
    @Override
    public void stop(){
        // Implementation
    }
    @Override
    public void fly(){
        // Implementation
    }
}

Now implementation classes implement those interfaces they are interested in and this helps to remove unnecessary code and is more readable

Next, let’s write a class to create objects of the implementation classes.

VehicleBuilder.java

public class VehicleBuilder {
    public static Car buildCar(){
        ToyHouse toyHouse=new ToyHouse();
        Car car = new Car();
        car.setPrice(15.00);
        car.setColor("green");
        car.start();
        return car;
        }
    public static Aeroplane buildAeroPlane(){
        Aeroplane aeroplane = new Aeroplane();
        aeroplane.setPrice(25.00);
        aeroplane.setColor("red");
        aeroplane.start();
        aeroplane.fly();
        return aeroplane;
    }
}

Summary (Interface Segregation Principle)

Interface Segregation Principle ensures small, focused, and highly cohesive software components. Interface Segregation Principle is easy to understand and simple to follow. But, identifying the distinct interfaces can be challenging to get the right role segregation. The Interface Segregation Principle a very powerful concept to master when developing Java applications.

If you have liked this concept and understood this story you might like Command Patterns which I wrote in the past another behavioral design pattern and is part of the GoF‘s formal list of design patterns. This pattern intends to encapsulate in an object all the data required for performing a given action (command)