Low-Level Design Tutorial 0/42 lessons ~6 min read Lesson 7

    Abstraction

    Abstraction focuses on essential behavior while hiding irrelevant detail.

    Course progress0%
    Focus
    9 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    Abstraction focuses on essential behavior while hiding irrelevant detail. Interfaces like PaymentGateway let booking code charge users without knowing Stripe vs PayPal internals — the hallmark of flexible LLD.

    Interviews reward abstractions at variation points: payment methods, notification channels, pricing strategies. Poor abstraction shows concrete classes wired everywhere, making extension painful.

    Java interfaces, abstract classes, and sealed hierarchies give you precise tools — this lesson shows when to use each.

    Understanding the topic

    Key concepts

    • Abstraction: simplified model of a concept emphasizing what matters for the problem.
    • Interface: contract without implementation — maximum flexibility.
    • Abstract class: shared partial implementation for closely related types.
    • Sealed interfaces: closed hierarchy when variants are known (PaymentMethod).
    • Dependency on abstractions, not concretes (DIP preview).
    • Leaky abstraction: when hidden details escape ( exposing SQL in repository ).

    Step-by-step explanation

    1. Find axes of change (new vehicle type, new payment provider).
    2. Define an interface capturing required operations.
    3. Implement concrete classes per variant.
    4. Inject interface into consumers via constructor.
    5. Keep interfaces small — one reason to change per interface (ISP preview).
    6. Avoid exposing implementation types from factory methods when possible.

    Informative example

    Notification abstraction — channel-specific details hidden behind one interface:

    java
    public interface Notifier {
    void send(Notification message);
    }
    public record Notification(String recipient, String body) {}
    public final class EmailNotifier implements Notifier {
    @Override
    public void send(Notification message) {
    // SMTP details hidden
    }
    }
    public final class SmsNotifier implements Notifier {
    @Override
    public void send(Notification message) {
    // SMS gateway hidden
    }
    }
    public final class AlertService {
    private final Notifier notifier;
    public AlertService(Notifier notifier) {
    this.notifier = notifier;
    }
    public void alertLowBalance(String userEmail, Money balance) {
    notifier.send(new Notification(userEmail, "Balance low: " + balance));
    }
    }

    AlertService depends on Notifier — swap EmailNotifier for SmsNotifier in tests without changing AlertService.

    Real-world use

    Real-world applications

    • Payment, storage, and messaging backends in LLD problems.
    • Plugin architectures within a single service.
    • Test doubles replacing expensive or external dependencies.

    Best practices

    • Name interfaces after capability (Readable, Payable), not implementation.
    • Do not abstract until a second implementation exists or is planned.
    • Prefer composition of interfaces over deep inheritance trees.
    • Document pre/post conditions on interface methods.
    • Use factory or DI to choose implementation at runtime.

    Common mistakes

    • One giant interface with unrelated methods.
    • Abstract class when interface suffices.
    • Returning concrete types from public APIs unnecessarily.
    • Abstraction for single-use code — YAGNI violation.

    Advanced interview questions

    Q1BeginnerWhat is abstraction in OOP?
    Modeling essential behavior while hiding implementation complexity.
    Q2BeginnerInterface vs abstract class?
    Interface for pure contract; abstract class when sharing code among related subclasses.
    Q3IntermediateWhen are sealed types useful?
    When variants are fixed and you want exhaustive switch handling in Java 21.
    Q4IntermediateWhat is a leaky abstraction?
    When callers must know implementation details to use the API correctly.
    Q5AdvancedDesign abstractions for a multi-payment checkout.
    PaymentMethod interface with authorize/capture; implementations per provider; Checkout depends on PaymentMethod only.

    Summary

    Abstractions hide detail and isolate variation. Interfaces at change boundaries keep designs extensible. Inject dependencies through abstractions for testability. Keep interfaces focused and intention-revealing. Avoid leaky or premature abstraction.

    Ready to mark this lesson complete?Track your journey across the entire course.