Design Pattern

Interface Segregation Principle (ISP)

Clean Java-only production-ready implementation.


Clients should not depend on methods they do not use.

A monolithic UserRepository interface forces every consumer to depend on methods they don't need.

Split into narrow, role-based interfaces.

// ─── EXAMPLE 1 ──────────────────────────────────────────────────────────────
// WHAT WE ARE IMPLEMENTING:
// A smart multifunction printer system where specialized machines implement
// only what they actually do.
//
// WHERE THE PRINCIPLE FITS IN:
// Split the monolithic Machine interface into highly cohesive interfaces:
// Printer, Scanner, and Fax. A basic printer implements only Printer,
// preventing unused methods.
// ────────────────────────────────────────────────────────────────────────────
import java.util.List;

// --- Bad: Fat interface ---
interface UserRepository {
    User findById(String id);
    void save(User user);
    void delete(String id);
    void update(User user);
    List<User> findActiveUsers();
    List<UserAudit> getAuditTrail(String userId);
    AnalyticsReport getAnalytics(String query);
    void exportToCSV();
}

// Every consumer depends on all methods, even if they only need one.

// --- Good: Segregated interfaces ---
interface UserReader {
    User findById(String id);
    List<User> findActiveUsers();
}

interface UserWriter {
    void save(User user);
    void update(User user);
    void delete(String id);
}

interface UserAuditReader {
    List<UserAudit> getAuditTrail(String userId);
}

interface UserAnalyticsReader {
    AnalyticsReport getAnalytics(String query);
}

// --- Concrete implementation ---
class PostgresUserRepository implements UserReader, UserWriter, UserAuditReader, UserAnalyticsReader {
    public User findById(String id) {
        System.out.println("  [DB] SELECT * FROM users WHERE id = " + id);
        return new User(id, "alice");
    }
    public void save(User user) { System.out.println("  [DB] INSERT INTO users ..."); }
    public void update(User user) { System.out.println("  [DB] UPDATE users ..."); }
    public void delete(String id) { System.out.println("  [DB] DELETE FROM users ..."); }
    public List<User> findActiveUsers() { return List.of(new User("1", "alice"), new User("2", "bob")); }
    public List<UserAudit> getAuditTrail(String userId) {
        return List.of(new UserAudit(userId, "LOGIN", 1000L));
    }
    public AnalyticsReport getAnalytics(String query) { return new AnalyticsReport("results"); }
}

// --- Clients depend only on what they need ---
class UserAuthService {
    private final UserReader reader;
    public UserAuthService(UserReader reader) { this.reader = reader; }
    public User authenticate(String id) { return reader.findById(id); }
}

class UserRegistrationService {
    private final UserWriter writer;
    public UserRegistrationService(UserWriter writer) { this.writer = writer; }
    public void register(User user) { writer.save(user); }
}

class UserAdminService {
    private final UserAuditReader auditReader;
    public UserAdminService(UserAuditReader auditReader) { this.auditReader = auditReader; }
    public void showAudit(String userId) {
        auditReader.getAuditTrail(userId).forEach(a -> System.out.println("  Audit: " + a));
    }
}

// Utility classes for demo
record User(String id, String name) {}
record UserAudit(String userId, String action, long timestamp) {}
record AnalyticsReport(String data) {}

public class Main {
    public static void main(String[] args) {
        PostgresUserRepository repo = new PostgresUserRepository();

        UserAuthService auth = new UserAuthService(repo);
        auth.authenticate("42");

        UserRegistrationService reg = new UserRegistrationService(repo);
        reg.register(new User("99", "bob"));

        UserAdminService admin = new UserAdminService(repo);
        admin.showAudit("42");
    }
}