Skip to content
intermediatePhase 49 · Low-Level Design

Abstraction

Define contracts with abstract classes and interfaces.

30m
0 problems
Topic Progress0%

Abstract Classes

Abstract classes define common behavior for related classes while leaving specific implementation to subclasses. They cannot be instantiated directly.

Abstract Class Definition

public abstract class Shape {
    // Abstract method: no implementation (subclasses MUST implement)
    public abstract double getArea();
    public abstract double getPerimeter();
    
    // Concrete method: has implementation (shared behavior)
    public void display() {
        System.out.println("Area: " + getArea());
    }
}

public class Circle extends Shape {
    private double radius;
    
    public Circle(double radius) {
        this.radius = radius;
    }
    
    @Override
    public double getArea() {
        return Math.PI * radius * radius;
    }
    
    @Override
    public double getPerimeter() {
        return 2 * Math.PI * radius;
    }
}

When to Use Abstract Classes

Use When Avoid When
Related classes share common behavior Classes are unrelated
You need non-public members You need multiple inheritance
You want to provide default implementations You only define contracts
Control over versioning Maximum flexibility needed

Template Method Pattern

Abstract classes enable the Template Method pattern:

public abstract class DataParser {
    // Template method (final: cannot be overridden)
    public final void parse(String filePath) {
        String data = readFile(filePath);
        Object parsed = processData(data);
        save(parsed);
    }
    
    // Abstract: subclasses must implement
    protected abstract Object processData(String data);
    
    // Concrete: shared implementation
    protected String readFile(String path) { ... }
    protected void save(Object data) { ... }
}

public class CSVParser extends DataParser {
    @Override
    protected Object processData(String data) {
        // CSV-specific parsing
    }
}

public class JSONParser extends DataParser {
    @Override
    protected Object processData(String data) {
        // JSON-specific parsing
    }
}

Abstract Class vs Regular Class

Regular Class
├── Can be instantiated
├── All methods can have implementations
└── Can exist without subclasses

Abstract Class
├── Cannot be instantiated directly
├── Can have abstract methods (no body)
├── Requires subclasses for abstract methods
└── Provides partial implementation

Interfaces

Interfaces define contracts that classes must follow. They specify what a class can do without defining how it does it.

Interface Definition

public interface PaymentProcessor {
    // Method signature (no body in older Java)
    PaymentResult processPayment(Money amount, PaymentDetails details);
    boolean refund(String transactionId, Money amount);
    
    // Constant (implicitly public static final)
    int MAX_RETRY_ATTEMPTS = 3;
}

// Implementation
public class StripePaymentProcessor implements PaymentProcessor {
    @Override
    public PaymentResult processPayment(Money amount, PaymentDetails details) {
        // Stripe-specific implementation
    }
    
    @Override
    public boolean refund(String transactionId, Money amount) {
        // Stripe-specific implementation
    }
}

Interface Design Principles

1. Interface Segregation (ISP):

// Bad: Fat interface
class OrderService implements Readable, Writable, Deletable, Searchable {
    // Forced to implement methods you might not need
}

// Good: Segregated interfaces
class OrderService implements Readable, Writable {
    // Only implement what's needed
}

2. Programming to Interface:

// Bad: Depends on concrete class
StripePaymentProcessor processor = new StripePaymentProcessor();

// Good: Depends on interface
PaymentProcessor processor = new StripePaymentProcessor();

3. Default Methods (Java 8+):

public interface Logger {
    void log(String message);
    
    // Default implementation
    default void logError(String message) {
        log("ERROR: " + message);
    }
}

Interface Methods

Method Type Purpose Example
Abstract Must be implemented void save();
Default Optional override default void log() {}
Static Utility methods static Validator create() {}

Multiple Interface Implementation

public interface Serializable { }
public interface Comparable<T> { }
public interface Cloneable { }

// Java allows implementing multiple interfaces
public class User implements Serializable, Comparable<User>, Cloneable {
    @Override
    public int compareTo(User other) { ... }
}

When to Use Each

Choosing between abstract classes and interfaces depends on design goals. This chapter provides a decision framework.

Decision Matrix

┌─────────────────────────────────────────────────────────────┐
│              Abstract Class vs Interface                     │
├──────────────────┬───────────────────┬──────────────────────┤
│ Criteria         │ Abstract Class    │ Interface            │
├──────────────────┼───────────────────┼──────────────────────┤
│ State (fields)   │ ✓ Can have       │ ✗ Only constants     │
│ Constructors     │ ✓ Yes            │ ✗ No                 │
│ Multiple inherit │ ✗ Single only    │ ✓ Multiple           │
│ Access modifiers │ ✓ Any            │ ✗ public only        │
│ Relationship     │ IS-A (strong)    │ CAN-DO (capability)  │
│ Versioning       │ Easier           │ Harder               │
│ Flexibility      │ Lower            │ Higher               │
└──────────────────┴───────────────────┴──────────────────────┘

Choose Abstract Class When:

1. Shared state and behavior:

// Abstract class: shares state (fields) and behavior
public abstract class Account {
    protected double balance;  // Shared state
    protected String id;       // Shared state
    
    public void deposit(double amount) {  // Shared behavior
        balance += amount;
    }
    
    public abstract double calculateInterest();  // Varies
}

2. Template Method pattern:

public abstract class GameEngine {
    public final void play() {
        initialize();
        while (!isGameOver()) {
            processTurn();
        }
        announceWinner();
    }
    protected abstract void processTurn();
}

Choose Interface When:

1. Unrelated classes share capability:

// Unrelated classes can be Comparable
public class Student implements Comparable<Student> { }
public class Product implements Comparable<Product> { }
public class Employee implements Comparable<Employee> { }

2. Multiple capabilities:

public class SmartPhone implements Camera, Phone, GPS, MusicPlayer {
    // Can have multiple capabilities
}

3. API contracts:

// Interface defines the contract
public interface UserRepository {
    User findById(String id);
    List<User> findAll();
    void save(User user);
}
// Any implementation must follow this contract

Hybrid Approach

// Abstract class provides partial implementation
public abstract class AbstractRepository<T> {
    protected EntityManager em;
    
    public T findById(String id) {
        return em.find(getType(), id);
    }
    
    public abstract Class<T> getType();
    
    public void save(T entity) {
        em.persist(entity);
    }
}

// Interface defines capability
public interface SoftDeletable {
    void softDelete();
    boolean isDeleted();
}

// Concrete class uses both
public class UserRepository extends AbstractRepository<User> 
        implements SoftDeletable {
    @Override
    public Class<User> getType() { return User.class; }
    
    @Override
    public void softDelete() { ... }
}

Rule of Thumb

  • Use interfaces for capabilities (Comparable, Serializable)
  • Use abstract classes for partial implementations of related classes
  • Prefer interfaces when unsure — they're more flexible
  • Use both when you need shared state AND multiple capabilities

Practice Problems

0/3solved
Design Abstraction System

Design a scalable Abstraction 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
Abstraction Scaling

How would you scale Abstraction 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
Abstraction Failure Modes

Analyze potential failure modes for Abstraction 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. Can an abstract class be instantiated directly?

Question 1 options

2. When should you prefer an interface over an abstract class?

Question 2 options

3. What is the Template Method pattern?

Question 3 options

4. What is the difference between IS-A and CAN-DO relationships?

Question 4 options

5. Which is NOT a valid reason to use an abstract class?

Question 5 options

Flashcards

Question

What is an abstract class?

Answer

A class that cannot be instantiated directly and may contain abstract methods (without implementation) that subclasses must implement. It provides partial implementation for related classes.

Question

What is an interface?

Answer

A contract that defines methods a class must implement. Interfaces specify what a class can do without defining how. They enable multiple inheritance of type.

Question

What is the Template Method pattern?

Answer

A pattern where an abstract class defines the skeleton of an algorithm (final method) with abstract steps that subclasses implement. The algorithm structure stays fixed; steps vary.

Question

Abstract class vs interface: state?

Answer

Abstract classes can have instance fields (state). Interfaces can only have public static final constants. Use abstract class when you need shared state.

Question

When to prefer interfaces over abstract classes?

Answer

When unrelated classes share a capability, when you need multiple inheritance of type, for API contracts, or when you need maximum flexibility.

Revision Notes

Key Takeaways

  • 1.Abstract classes provide partial implementation; interfaces define pure contracts
  • 2.Abstract classes share state; interfaces share capability
  • 3.Use Template Method pattern for algorithm skeletons in abstract classes
  • 4.Prefer interfaces when flexibility and multiple inheritance are needed
  • 5.Choose based on relationship: IS-A → abstract class, CAN-DO → interface

Interview Tips

  • Explain why you chose abstract class vs interface in your design
  • Show how Template Method pattern enforces algorithm structure
  • Discuss Interface Segregation when designing multiple related interfaces
  • Mention programming to interface principle when showing dependency management

Cheat Sheet

Abstraction - Cheat Sheet

Abstract Class:

  • Cannot instantiate directly
  • Can have state (fields)
  • Can have constructors
  • Single inheritance
  • IS-A relationship
  • Use for related classes with shared behavior

Interface:

  • Cannot have state (only constants)
  • No constructors
  • Multiple implementation
  • CAN-DO relationship
  • Use for capabilities/contracts

Decision:

Need Choice
Shared state Abstract class
Multiple types Interface
Template method Abstract class
Unrelated capabilities Interface
Default implementations Both (Java 8+)

Template Method:
Abstract class defines algorithm skeleton.
Subclasses implement specific steps.