Skip to content
intermediatePhase 49 · Low-Level Design

Interfaces in LLD

Define clear contracts between components for loose coupling.

30m
0 problems
Topic Progress0%

Interface Design

Well-designed interfaces are contracts that define clear, focused behaviors. They are the backbone of flexible LLD.

Interface Design Principles

1. Small and Focused

// BAD: Fat interface
public interface UserService {
    User getUser(String id);
    void createUser(User user);
    void deleteUser(String id);
    void sendEmail(String to, String msg);
    List<Order> getUserOrders(String userId);
    void generateReport();
}

// GOOD: Focused interfaces
public interface UserReader {
    User getUser(String id);
    List<User> findAll();
}

public interface UserWriter {
    void createUser(User user);
    void updateUser(User user);
    void deleteUser(String id);
}

public interface UserNotifier {
    void sendWelcomeEmail(User user);
}

2. Stable Abstractions

// Interface should change infrequently
public interface PaymentProcessor {
    // Core methods that rarely change
    PaymentResult process(Money amount, PaymentDetails details);
    boolean refund(String transactionId, Money amount);
}

// Implementation can change frequently
public class StripeProcessor implements PaymentProcessor {
    // Stripe-specific logic changes as Stripe API evolves
}

3. Program to Interface

// Good: Depends on abstraction
public class OrderService {
    private final PaymentProcessor processor;
    
    public OrderService(PaymentProcessor processor) {
        this.processor = processor;
    }
}

// Bad: Depends on concrete class
public class OrderService {
    private final StripeProcessor processor; // Tightly coupled!
}

Interface Naming

Pattern Example When
Adjective Comparable, Serializable Capability
Noun Repository, Factory Role
-able/-ible Cacheable, Validatable Capability
I-prefix (C#) IUserService Convention

Interface Methods

public interface Repository<T> {
    // Query methods
    Optional<T> findById(String id);
    List<T> findAll();
    
    // Command methods
    void save(T entity);
    void delete(String id);
    
    // Default methods (optional implementation)
    default boolean exists(String id) {
        return findById(id).isPresent();
    }
    
    // Static utility
    static <T> Repository<T> empty() {
        return new EmptyRepository<>();
    }
}

Interface Segregation

ISP in LLD means designing interfaces that are small and focused, so implementers only need to implement what they use.

Segregation by Role

// Bad: One interface for all operations
public interface DataStore {
    byte[] read(String key);
    void write(String key, byte[] data);
    void delete(String key);
    List<String> list(String prefix);
    void flush();
    void close();
}

// Good: Segregated by use case
public interface Readable {
    byte[] read(String key);
}

public interface Writable {
    void write(String key, byte[] data);
}

public interface Deleteable {
    void delete(String key);
}

public interface Listable {
    List<String> list(String prefix);
}

// Implement only what you need
class ReadOnlyCache implements Readable {
    public byte[] read(String key) { ... }
}

class FullStore implements Readable, Writable, Deleteable, Listable {
    // Implements all
}

Segregation by Client

// Different clients need different interfaces
public interface AdminOperations {
    void deleteUser(String id);
    void resetPassword(String id);
    void suspendAccount(String id);
}

public interface UserOperations {
    User getProfile();
    void updateProfile(User user);
}

public interface GuestOperations {
    User login(String email, String password);
    void register(User user);
}

// Each role implements only its interface
class AdminService implements AdminOperations { }
class UserService implements UserOperations { }
class AuthService implements GuestOperations { }

Segregation by Operation Type

// Read vs Write separation (CQRS lite)
public interface ReadModel {
    Order getOrder(String id);
    List<Order> getUserOrders(String userId);
}

public interface WriteModel {
    void createOrder(Order order);
    void cancelOrder(String orderId);
}

// Different implementations for different needs
class OrderQueryService implements ReadModel {
    // Optimized for reads (uses cache, read replica)
}

public class OrderCommandService implements WriteModel {
    // Optimized for writes (uses primary DB)
}

ISP Benefits

  1. Easier to implement: Fewer methods to code
  2. Easier to test: Mock only needed methods
  3. Easier to understand: Clear, focused contracts
  4. Better composability: Mix and match interfaces
  5. Less breaking: Changes affect fewer implementations

Dependency Inversion

DIP through interfaces creates loose coupling between high-level and low-level modules.

The Inversion

Traditional:                    DIP:
High → Low                      High → Interface ← Low

OrderService → MySQLDatabase    OrderService → Database ← MySQLDatabase
(Tight coupling)                (Loose coupling)

Interface as Contract

// Interface defines the contract
public interface NotificationService {
    void send(User user, String message);
    List<Notification> getHistory(String userId);
}

// Multiple implementations
public class EmailNotification implements NotificationService {
    public void send(User user, String message) {
        // Email implementation
    }
}

public class SMSNotification implements NotificationService {
    public void send(User user, String message) {
        // SMS implementation
    }
}

public class PushNotification implements NotificationService {
    public void send(User user, String message) {
        // Push implementation
    }
}

// Consumer depends on interface, not implementation
public class OrderService {
    private final NotificationService notifications;
    
    public OrderService(NotificationService notifications) {
        this.notifications = notifications;
    }
    
    public void completeOrder(Order order) {
        // Process order...
        notifications.send(order.getUser(), "Order complete!");
    }
}

Interface-Based Testing

// Easy to test with mocks
public class OrderServiceTest {
    @Test
    void shouldNotifyUserOnOrderComplete() {
        // Mock the interface
        NotificationService mockNotifications = mock(NotificationService.class);
        OrderService service = new OrderService(mockNotifications);
        
        service.completeOrder(testOrder);
        
        // Verify interaction
        verify(mockNotifications).send(any(), contains("Order complete"));
    }
}

Interface Hierarchies

// Base repository interface
public interface Repository<T> {
    Optional<T> findById(String id);
    void save(T entity);
}

// Extended for specific features
public interface SearchableRepository<T> extends Repository<T> {
    List<T> search(String query);
}

public interface CacheableRepository<T> extends Repository<T> {
    void invalidateCache(String id);
}

// Concrete interface combines capabilities
public interface ProductRepository extends SearchableRepository<Product>, 
                                         CacheableRepository<Product> {
    List<Product> findByCategory(String category);
}

Common Interface Patterns in LLD

Pattern Interface Purpose
Repository UserRepository Data access
Service PaymentService Business logic
Factory NotificationFactory Object creation
Strategy SortStrategy Algorithm selection
Observer EventListener Event handling
Adapter ExternalAPI Interface conversion

Practice Problems

0/3solved
Design Interfaces in LLD System

Design a scalable Interfaces in LLD system. Cover high-level architecture, data model, and API design.

Solution
// Complete system design:
// - Functional + Non-functional requirements
// - Capacity estimation
// - Data model (SQL/NoSQL choice)
// - API endpoints
// - Component architecture
// - Scaling strategy
// - Monitoring & reliability
Interfaces in LLD Scaling

How would you scale Interfaces in LLD to handle 10x the current load? Identify bottlenecks and solutions.

Solution
// Scaling approach:
// 1. Load balancing
// 2. Database sharding/replication
// 3. Cache layer (Redis)
// 4. CDN for static assets
// 5. Async processing (queues)
// 6. Microservices decomposition
Interfaces in LLD Failure Modes

Analyze potential failure modes for Interfaces in LLD and design mitigation strategies.

Solution
// Failure mitigation:
// 1. Redundancy (multi-AZ)
// 2. Circuit breakers
// 3. Retry with backoff
// 4. Dead letter queues
// 5. Health checks
// 6. Graceful degradation

Quiz

1. What is the primary goal of interface segregation in LLD?

Question 1 options

2. How does Dependency Inversion improve testability?

Question 2 options

3. What is 'programming to interface'?

Question 3 options

4. Which is an example of interface segregation?

Question 4 options

5. What is an interface hierarchy?

Question 5 options

Flashcards

Question

What are the key principles of interface design?

Answer

Small and focused, stable abstractions, program to interface, clear naming, and appropriate method granularity.

Question

What is Interface Segregation?

Answer

Splitting large interfaces into smaller, focused ones. Implementers only need to implement methods they actually use. Reduces coupling.

Question

How does Dependency Inversion work with interfaces?

Answer

High-level modules depend on interfaces, not concrete implementations. Low-level modules implement the interfaces. Both depend on abstractions.

Question

What are common interface patterns in LLD?

Answer

Repository (data access), Service (business logic), Factory (creation), Strategy (algorithms), Observer (events), Adapter (conversion).

Question

What is interface hierarchy?

Answer

Extended interfaces that inherit from base interfaces. BaseRepository → SearchableRepository → ProductRepository. Each level adds specialized methods.

Revision Notes

Key Takeaways

  • 1.Design interfaces to be small, focused, and stable
  • 2.Apply ISP: split large interfaces into smaller, role-specific ones
  • 3.DIP through interfaces enables loose coupling and easy testing
  • 4.Program to interfaces throughout your design
  • 5.Use interface hierarchies for specialized variations

Interview Tips

  • Show interface-based design when discussing flexibility
  • Demonstrate how interfaces enable easy testing through mocking
  • Explain ISP when discussing fat interface problems
  • Use interface hierarchies to show extensible designs

Cheat Sheet

Interfaces in LLD - Cheat Sheet

Interface Design:

  • Small and focused (1-3 methods ideal)
  • Stable (change infrequently)
  • Program to interface, not implementation
  • Clear naming: -able/-ible for capabilities

Interface Segregation:

  • Split by role: AdminOps, UserOps, GuestOps
  • Split by operation: Readable, Writable
  • Split by client: each client gets its own

Dependency Inversion:

  • High-level → Interface ← Low-level
  • Enables mocking for testing
  • Loose coupling between modules

Common Patterns:

Pattern Interface
Repository UserRepository
Service PaymentService
Factory NotificationFactory
Strategy SortStrategy
Observer EventListener