Java

Replacing Conditionals with Polymorphism

Complex conditional logic is one of the most common sources of bugs and maintenance headaches. This article covers techniques to replace switch statements and if-else chains with polymorphic designs that are easier to extend, test, and maintain.

📋 At a Glance

AspectDetails
Patterns CoveredStrategy, State, Pattern Matching
Primary BenefitOpen for extension, closed for modification
Best ForType-based switches, algorithm selection
Java Version8+ (lambdas), 17+ (pattern matching)
Risk LevelMedium (requires careful testing)

🎯 What You'll Learn

  • Strategy Pattern for algorithm selection
  • State Pattern for state-dependent behavior
  • Pattern Matching (Java 17+) for concise conditionals
  • Enum-based dispatch for simple cases
  • Rule Engine Pattern for complex business rules
  • When to keep conditionals (not everything needs polymorphism)

🔥 Production Story: The Payment Switch That Grew Out of Control

A payment service started with a simple switch:

JAVA(8 lines)
Code
Loading syntax highlighter...

Three years later:

JAVA(16 lines)
Code
Loading syntax highlighter...
The problems:
  • Adding payment type required changes in 12 switch statements across codebase
  • Each payment type's code mixed together (no isolation)
  • Testing required understanding entire switch
  • Different teams couldn't work independently
The fix: Strategy Pattern
JAVA(13 lines)
Code
Loading syntax highlighter...

🧠 Mental Model: Conditional to Polymorphism

TEXT(25 lines)
Code
Loading syntax highlighter...

🔬 Deep Dive

Pattern 1: Strategy Pattern

Use when: Different algorithms can be selected at runtime.
JAVA(75 lines)
Code
Loading syntax highlighter...
Adding new shipping method:
  1. Create new @Component class implementing ShippingCalculator
  2. That's it! Spring auto-discovers and registers it.

Pattern 2: State Pattern

Use when: Object behavior depends on its current state.
JAVA(102 lines)
Code
Loading syntax highlighter...

Pattern 3: Pattern Matching (Java 17+)

Use when: Need concise conditionals, fixed set of types.
JAVA(39 lines)
Code
Loading syntax highlighter...

Pattern 4: Enum with Behavior

Use when: Simple cases, limited number of fixed types.
JAVA(32 lines)
Code
Loading syntax highlighter...

Pattern 5: Rule Engine for Complex Conditions

Use when: Many complex, changeable business rules.
JAVA(57 lines)
Code
Loading syntax highlighter...

⚠️ Common Mistakes

Mistake 1: Over-Engineering Simple Cases

JAVA(9 lines)
Code
Loading syntax highlighter...

Mistake 2: Forgetting Null/Default Cases

JAVA(14 lines)
Code
Loading syntax highlighter...

🐛 Debug This: The Missing Discount Type

A developer reports: "We added a new discount type LOYALTY_POINTS but customers aren't getting their discounts. The switch compiles fine!"

JAVA(27 lines)
Code
Loading syntax highlighter...
Why doesn't the compiler catch this bug? How would you prevent it?

✅ Solution:
The bug is the silent default case - when a new enum value is added, it falls through to default instead of causing a compile error.
Problems:
  1. default case swallows new enum values silently
  2. No compiler warning for unhandled enum cases
  3. Business logic silently fails
Prevention strategies:
JAVA(19 lines)
Code
Loading syntax highlighter...
The lesson: Avoid default cases in enum switches when possible. Use exhaustive switches (Java 17+) or Strategy pattern to ensure all cases are handled.

💻 Exercises

Exercise 1: Convert Switch to Strategy

⭐⭐ Difficulty: Medium | ⏱️ Time: 15 minutes

Task: Refactor this switch to Strategy pattern.
JAVA(9 lines)
Code
Loading syntax highlighter...
✅ Solution:
JAVA(27 lines)
Code
Loading syntax highlighter...

Exercise 2: Apply State Pattern

⭐⭐ Difficulty: Medium | ⏱️ Time: 20 minutes

Task: Replace these conditionals with State pattern.
JAVA(21 lines)
Code
Loading syntax highlighter...
✅ Solution:
JAVA(25 lines)
Code
Loading syntax highlighter...

Exercise 3: Use Enum with Behavior

⭐⭐ Difficulty: Medium | ⏱️ Time: 15 minutes

Task: Add behavior to this enum to eliminate the switch.
JAVA(12 lines)
Code
Loading syntax highlighter...
✅ Solution:
JAVA(21 lines)
Code
Loading syntax highlighter...

Exercise 4: Pattern Matching (Java 17+)

⭐⭐⭐ Difficulty: Medium-Hard | ⏱️ Time: 20 minutes

Task: Refactor to use pattern matching.
JAVA(13 lines)
Code
Loading syntax highlighter...
✅ Solution:
JAVA(10 lines)
Code
Loading syntax highlighter...

Exercise 5: Rule Engine Pattern

⭐⭐⭐⭐ Difficulty: Hard | ⏱️ Time: 25 minutes

Task: Replace nested conditionals with Rule Engine.
JAVA(14 lines)
Code
Loading syntax highlighter...
✅ Solution:
JAVA(38 lines)
Code
Loading syntax highlighter...

🎤 Senior-Level Interview Questions

Q1: When should you keep a switch instead of using polymorphism?

Answer:
  • Few cases (2-3) that won't grow
  • Simple, one-liner cases
  • Performance-critical code
  • Pattern matching is cleaner (Java 17+)
  • Cases aren't really "types" but just values

Q2: Strategy vs State - what's the difference?

Answer:
  • Strategy: Client chooses which algorithm to use
  • State: Object changes its own behavior based on internal state
  • Strategy = same object, different algorithms
  • State = same algorithm, different behavior per state

📝 Summary

ApproachUse When
StrategyAlgorithm selection, extensible
StateBehavior depends on state
Pattern MatchingFixed types, Java 17+
Enum with behaviorSimple, fixed cases
Rule EngineComplex business rules
Keep Switch2-3 simple cases

📅 Review Schedule for This Article

DayTaskTime
Day 1Review Strategy vs State vs Pattern Matching table5 min
Day 3Redo Exercise 1 (Convert Switch to Strategy)15 min
Day 7Answer interview questions without looking10 min
Day 14Redo Debug This (Missing Discount Type)10 min
Day 30Find one switch in your project that could use Strategy15 min

Next in series: [Part 8: Null Handling Patterns]