Java
Enums
Interfaces
Programming
Software Development

Why would an Enum implement an Interface?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Java, an enum implementing an interface is a concise way to combine fixed constants with polymorphic behavior. This pattern is useful when each enum constant represents a strategy or command. It keeps behavior close to domain values and avoids large switch blocks scattered across the codebase.

What You Gain by Combining Enum and Interface

An interface defines behavior contract. Enum constants provide a closed set of implementations.

Benefits:

  • Compile-time safety for allowed options.
  • No accidental creation of invalid strategy objects.
  • Centralized behavior per constant.
  • Cleaner call sites using polymorphism.
java
1public interface FeePolicy {
2    double apply(double amount);
3}
4
5public enum PaymentType implements FeePolicy {
6    CARD {
7        @Override
8        public double apply(double amount) {
9            return amount * 1.02;
10        }
11    },
12    BANK_TRANSFER {
13        @Override
14        public double apply(double amount) {
15            return amount;
16        }
17    },
18    WALLET {
19        @Override
20        public double apply(double amount) {
21            return amount * 1.01;
22        }
23    }
24}

Each constant is a concrete behavior implementation behind one interface.

Replacing Switch Chains with Polymorphism

Without enum-interface design, code often grows switch statements in multiple classes.

java
double total = paymentType.apply(100.0);

This is easier to extend safely than editing repeated switch logic everywhere.

If a new payment type is added, compiler-guided enum changes are localized and explicit.

Strategy Pattern with Bounded Options

This approach is a strong fit when strategy options are finite and stable.

Examples:

  • Tax rule category
  • Export format behavior
  • Retry policy family
  • Scoring mode

Because enums are closed sets, they naturally express "known finite policy set" better than open class hierarchies.

Shared State and Constructor Parameters

Enums can hold fields and constructor parameters, so behavior can reuse common configuration.

java
1public interface DiscountRule {
2    double discount(double amount);
3}
4
5public enum CustomerTier implements DiscountRule {
6    STANDARD(0.00),
7    GOLD(0.10),
8    PLATINUM(0.20);
9
10    private final double rate;
11
12    CustomerTier(double rate) {
13        this.rate = rate;
14    }
15
16    @Override
17    public double discount(double amount) {
18        return amount * rate;
19    }
20}

This keeps data and behavior cohesive without extra classes.

When Not to Use This Pattern

Do not force enum-interface design when behavior set is unbounded or plugin-driven.

Prefer regular classes when:

  • Implementations must be loaded dynamically.
  • Third-party modules add behaviors.
  • Behavior family changes frequently and independently of enum constants.

In those cases, classic interface plus class implementations is more flexible.

Testing and Maintainability

Enum strategies are easy to test because each constant is deterministic.

java
1import static org.junit.jupiter.api.Assertions.assertEquals;
2import org.junit.jupiter.api.Test;
3
4class CustomerTierTest {
5    @Test
6    void goldDiscountIsTenPercent() {
7        assertEquals(20.0, CustomerTier.GOLD.discount(200.0));
8    }
9}

This style reduces wiring complexity and keeps behavior discoverable in one source file.

Design Tradeoffs

Advantages:

  • Compact architecture.
  • Strong type safety.
  • Eliminates many switch statements.

Tradeoffs:

  • Enum file can become large if overused.
  • Harder to extend externally compared with class-based plugin models.
  • Can blur responsibility if business logic becomes too heavy per constant.

Use it for concise, stable, domain-driven behavior sets.

Common Pitfalls

  • Putting too much logic inside enum constants and creating bloated enum classes.
  • Using enum-interface pattern where runtime extensibility is required.
  • Duplicating data and behavior across constants instead of shared helpers.
  • Replacing every switch with enum behavior even when simple mapping is clearer.
  • Ignoring unit tests because enum behavior "looks obvious."

Summary

  • Enum implementing interface is a clean way to model finite polymorphic behavior.
  • It works especially well for strategy-like domain options.
  • The pattern improves type safety and reduces scattered switch logic.
  • Avoid it when behavior must be open for dynamic extension.
  • Keep enum constants focused and test each behavior explicitly.

Course illustration
Course illustration

All Rights Reserved.