27 Oct 2023



Intermediate

The Interface Segregation Principle (ISP) states that "Clients should not be forced to implement interfaces they don't use. Instead of one large interface, many small interfaces are preferred based on groups of methods, each one serving one sub-module."

In simpler terms, this means that each interface should only contain the methods that are needed by the classes that implement it. Avoid creating large, general interfaces that contain methods that are not used by all of the classes that implement them.

Examples of Interface Segregation Principle (ISP) along with their corresponding solutions:

Example 1: Violating ISP in Vehicle Interface

Problem Description: Imagine a single, monolithic interface called Vehicle that all types of vehicles, such as cars, bicycles, and airplanes, are required to implement. This interface includes methods like startEngine(), accelerate(), brake(), and fly(). Not all vehicles can perform all these actions.

Code Snippet (Violation):

interface Vehicle {
    void startEngine();
    void accelerate();
    void brake();
    void fly();
}

class Car implements Vehicle {
    void startEngine() {
        // Implementation
    }

    void accelerate() {
        // Implementation
    }

    void brake() {
        // Implementation
    }

    void fly() {
        // Unnecessary implementation
    }
}

Solution: Adhering to ISP in Vehicle Design

Solution Description: To follow the Interface Segregation Principle (ISP), we break down the monolithic Vehicle interface into smaller, more specialized interfaces. For example, MotorizedVehicle for vehicles with engines, Bicycle for non-motorized vehicles, and FlyingVehicle for aircraft. Each type of vehicle can then implement only the interfaces that match their capabilities.

Code Snippet (Adhering to ISP):

interface MotorizedVehicle {
    void startEngine();
    void accelerate();
    void brake();
}

interface Bicycle {
    void pedal();
    void brake();
}

interface FlyingVehicle {
    void takeOff();
    void fly();
    void land();
}

class Car implements MotorizedVehicle {
    void startEngine() {
        // Implementation
    }

    void accelerate() {
        // Implementation
    }

    void brake() {
        // Implementation
    }
}

In this example, the adherence to ISP ensures that each type of vehicle can implement only the interfaces that correspond to their specific capabilities, making the code more modular, maintainable, and efficient.


Example 2: Violating ISP in User Permissions System

Problem Description: In a User Permissions System, there's a single, monolithic UserPermissions interface that all user permission classes must implement. This interface includes methods for granting and checking read, write, and delete permissions, among other things. However, not all user permission classes require all these methods.

Code Snippet (Violation):

interface UserPermissions {
    void grantReadPermission(User user);
    void grantWritePermission(User user);
    void grantDeletePermission(User user);
    void checkReadPermission(User user);
    void checkWritePermission(User user);
    void checkDeletePermission(User user);
    // Many other methods...
}

class BasicUserPermissions implements UserPermissions {
    void grantReadPermission(User user) {
        // Implementation
    }

    // Unnecessary implementation for other methods
}

Solution: Adhering to ISP in User Permissions System

Solution Description: To follow the Interface Segregation Principle (ISP), we can break down the monolithic UserPermissions interface into smaller, more specialized interfaces based on the types of permissions. For example, ReadPermission, WritePermission, and DeletePermission. Each user permission class can then implement only the interfaces relevant to its specific permissions.

Code Snippet (Adhering to ISP):

interface ReadPermission {
    void grantReadPermission(User user);
    void checkReadPermission(User user);
}

interface WritePermission {
    void grantWritePermission(User user);
    void checkWritePermission(User user);
}

interface DeletePermission {
    void grantDeletePermission(User user);
    void checkDeletePermission(User user);
}

class BasicUserPermissions implements ReadPermission {
    void grantReadPermission(User user) {
        // Implementation
    }

    void checkReadPermission(User user) {
        // Implementation
    }
}

In this example, adhering to ISP ensures that user permission classes implement only the interfaces related to their specific permissions, avoiding the need for unnecessary method implementations for permissions they don't require.

Example 3: Violating ISP with a Monolithic Interface

Problem Description: The problem here is that there's a single, large interface called Notification for a notification system, but not all clients using this interface require all the methods it contains.

Code Snippet ( ISP Violation):

interface Notification {
    void sendEmail();
    void sendSMS();
    void sendPushNotification();
}

class EmailClient implements Notification {
    void sendEmail() {
        // Implementation
    }

    void sendSMS() {
        // Unnecessary implementation
    }

    void sendPushNotification() {
        // Unnecessary implementation
    }
}

Solution Description: To adhere to the Interface Segregation Principle (ISP), the monolithic Notification interface is split into smaller, more focused interfaces: EmailNotification, SMSNotification, and PushNotification. Clients can now implement only the interfaces they actually need, avoiding unnecessary method implementations.

Code Snippet (Adhering to ISP):

interface EmailNotification {
    void sendEmail();
}

interface SMSNotification {
    void sendSMS();
}

interface PushNotification {
    void sendPushNotification();
}

class EmailClient implements EmailNotification {
    void sendEmail() {
        // Implementation
    }
}

Example 4: ISP Violation with a Large Configuration Interface

Problem Description: The problem in this case is that there is a configuration interface (Configuration) with many methods, and clients must implement all of them, even if they don't need all the configuration options.

Code Snippet ( ISP Violation):

interface Configuration {
    void setServerAddress(String address);
    void setPort(int port);
    void setUsername(String username);
    void setPassword(String password);
    void setCacheSize(int cacheSize);
    // Many other methods...
}

class DatabaseClient implements Configuration {
    void setServerAddress(String address) {
        // Implementation
    }

    // Unnecessary implementation for other methods
}

Solution Description: To follow ISP, the large Configuration interface is broken down into smaller, more specialized interfaces: ServerConfig, AuthenticationConfig, and CacheConfig. Clients can now implement only the interfaces relevant to their specific needs, avoiding the burden of implementing unnecessary methods.

Code Snippet (Adhering to ISP):

interface ServerConfig {
    void setServerAddress(String address);
    void setPort(int port);
}

interface AuthenticationConfig {
    void setUsername(String username);
    void setPassword(String password);
}

interface CacheConfig {
    void setCacheSize(int cacheSize);
}

class DatabaseClient implements ServerConfig, AuthenticationConfig {
    void setServerAddress(String address) {
        // Implementation
    }

    void setUsername(String username) {
        // Implementation
    }
}
solid-principles
interface-sugregation-principle