Back to Enum
Q2Question 2 of 2

How does an enum with an abstract method implement the Strategy pattern?

Key Concepts
  • An enum can declare an abstract method that each constant must implement
  • Each constant becomes an anonymous class with its own implementation
  • This is the Strategy pattern: the behavior varies by constant, selected at runtime
  • Type-safe and closed: no one can add a new strategy without modifying the enum source
  • Common in banking: different interest calculation strategies per account type

Definition

Declare an abstract method on the enum, and each constant provides its own implementation. The enum constants become the strategies, selected by type at runtime.

Enum-based Strategy pattern:

  • Abstract method on enum: Each constant must override it with its own behavior.
  • Each constant is a strategy: SAVINGS.calculateInterest(...) uses a different formula than LOAN.calculateInterest(...).
  • Closed set: Only the defined constants can provide strategies. No external code can add one.
  • Type-safe selection: Pass the enum constant to select the strategy. No string matching or if-else chains.

The bank has three types of interest calculation forms: one for savings, one for current, one for loans. Each form has the same header (abstract method signature) but different calculation steps (each constant's implementation). The teller picks the form matching the account type.

Understanding the Concepts

How does it work?

JAVA
public enum AccountType {
    SAVINGS {
        @Override
        public BigDecimal calculateInterest(BigDecimal balance) {
            return balance.multiply(new BigDecimal("0.04"));  // 4%
        }
    },
    CURRENT {
        @Override
        public BigDecimal calculateInterest(BigDecimal balance) {
            return BigDecimal.ZERO;  // no interest
        }
    },
    LOAN {
        @Override
        public BigDecimal calculateInterest(BigDecimal balance) {
            return balance.multiply(new BigDecimal("0.085"));  // 8.5%
        }
    };

    // Abstract method: every constant MUST implement this
    public abstract BigDecimal calculateInterest(BigDecimal balance);
}

// Usage: no if-else, no switch – polymorphic dispatch on the enum
AccountType type = AccountType.SAVINGS;
BigDecimal interest = type.calculateInterest(new BigDecimal("500000"));
System.out.println(interest);  // 20000

Adding a new account type forces you to implement calculateInterest() – the compiler ensures completeness.

How is this the Strategy pattern?

The Strategy pattern says: define a family of algorithms, encapsulate each one, and make them interchangeable.

  • Family of algorithms: The three interest calculation formulas.
  • Encapsulated: Each constant contains its own implementation.
  • Interchangeable: Pass the enum constant to select the strategy.

Without enum:

JAVA
// BAD: if-else chain, not extensible, easy to forget a case
if (type.equals("SAVINGS")) { ... }
else if (type.equals("CURRENT")) { ... }
else if (type.equals("LOAN")) { ... }

With enum: the dispatch is built into the type system. No if-else needed.

When should you use enum Strategy vs interface Strategy?

| Enum Strategy | Interface Strategy |
|---|---|
| Closed set of strategies | Open set (new strategies can be added) |
| All strategies in one file | Strategies in separate classes |
| Simple, few strategies | Complex strategies with dependencies |
| No Spring injection needed | Strategies need injected dependencies |

What should a senior engineer know?

  • Combine with fields and methods. Each constant can have its own data (fee rates, limits) and behavior (calculation methods).
  • Use sealed interfaces (Java 17+) for open-but-controlled strategy sets: sealed interface Strategy permits FixedRate, FloatingRate, ZeroRate {}.
  • In Spring, use interface-based Strategy when strategies need injected services (repository, external API). Enum constants cannot have Spring-managed dependencies.

What are common mistakes?

A common mistake is not understanding the concept fully before using it in production banking applications.

Wrong approach:

JAVA
package com.bank.service;

public class TransferService {
    public void transfer(String fromAccount, String toAccount, double amount) {
        // WRONG: using double for money
        double balance = getBalance(fromAccount);
        balance = balance - amount;
    }
    private double getBalance(String id) { return 10000.0; }
}

Correct approach:

JAVA
package com.bank.service;

import java.math.BigDecimal;

public class TransferService {
    public void transfer(String fromAccount, String toAccount, BigDecimal amount) {
        // CORRECT: using BigDecimal for money
        BigDecimal balance = getBalance(fromAccount);
        balance = balance.subtract(amount);
    }
    private BigDecimal getBalance(String id) { return new BigDecimal("10000.00"); }
}

Always use BigDecimal for monetary calculations in banking systems to avoid floating-point precision errors.

What are the edge cases?

Edge cases can cause unexpected behavior in banking applications. Here are some to watch for.

JAVA
package com.bank.edge;

public class EdgeCaseDemo {
    public static void main(String[] args) {
        // Edge case 1: null handling
        String accountId = null;
        try {
            System.out.println(accountId.length());
        } catch (NullPointerException e) {
            System.out.println("Null account ID");
        }

        // Edge case 2: empty vs null
        String emptyId = "";
        System.out.println(emptyId.isEmpty());  // true
        System.out.println(emptyId == null);     // false

        // Edge case 3: boundary values
        java.math.BigDecimal zero = java.math.BigDecimal.ZERO;
        java.math.BigDecimal negativeBalance = new java.math.BigDecimal("-0.01");
        System.out.println(zero.compareTo(negativeBalance) > 0);  // true
    }
}
TEXT
Null account ID
true
false
true

Always test with null values, empty strings, boundary values, and negative amounts in banking applications.

What are common interview follow-up questions?

Interviewers often follow up with these related questions:

  • How does this concept apply to a high-throughput banking transaction system?
  • What are the performance implications in a production environment?
  • How would you debug issues related to this concept?
  • What tools would you use to monitor this in production?
  • How does this behave differently in Java 8 vs Java 17+?

When answering follow-up questions, always relate your answer back to practical experience. For example, at National Bank of India, Rajesh debugged a production issue related to this concept by using JFR recordings and heap dumps. Providing concrete examples from banking systems shows the interviewer that you understand both the theory and the practice.

Visual Overview

DIAGRAM
  enum AccountType:
    SAVINGS  → calculateInterest: balance * 4%
    CURRENT  → calculateInterest: 0
    LOAN     → calculateInterest: balance * 8.5%

  type.calculateInterest(500000)
    │ polymorphic dispatch on the enum constant
    ▼
  SAVINGS → 20000
  CURRENT → 0
  LOAN    → 42500

  No if-else, no switch – behavior is built into the type.

Key Takeaway

An enum with an abstract method implements the Strategy pattern by forcing each constant to provide its own implementation. The behavior varies by constant and is selected at runtime through polymorphic dispatch, with no if-else or switch needed.

This is ideal for small, closed sets of strategies like account-type-specific interest calculations. Adding a new constant automatically requires implementing the abstract method, so the compiler ensures completeness.

One sentence to remember: declare an abstract method on the enum and each constant becomes a type-safe strategy with its own implementation.

---

Share
Use ← → arrow keys to navigate