Enums in Java aren’t just for storing constants - they can also hold behaviour, making them a great tool for writing cleaner, more maintainable, and type-safe code. They might not always be the first solution that comes to mind, but once you see them in action, their clarity and self-contained logic can be a real game-changer.
Enum-Based Strategy Pattern
The Strategy Pattern is used when you want to define a set of interchangeable behaviors and make them easily switchable at runtime. Normally, we implement this pattern using interfaces and concrete classes, but Enums provide a cleaner, more concise alternative.
When to Use Enum-Based Strategy Pattern?
Fixed Set of Strategies – When you have a known, finite number of strategies at compile time.
Behavior Encapsulation – When you want to encapsulate behavior within a type-safe and self-contained structure.
Avoiding Boilerplate Code – When traditional class-based strategy patterns feel overly verbose for simple use cases.
Let's say you are building a payment system that supports different payment methods: Credit Card, PayPal, and Bitcoin. Each payment method has a different way of processing payments
Use the Enum in a Payment Processor
Enum-Based Command Pattern
In this pattern, each enum constant represents a command. By defining an abstract method (say, execute
) inside the enum, you allow each constant to provide its own implementation. This is especially useful when you need a clean, centralized way to map strings or tokens to behavior.
Dynamic lookup and execution through enums are more maintainable than external maps or conditionals.
When to Use It:
When your application has discrete commands (actions) that need to be executed based on user input or configuration.
When you want a single, centralized place for all command behaviors.
The enum serves as both a registry of available commands and their implementations, avoiding bulky switch statements or external mappings.
Enum as a Factory (Creation of Objects)
You can use enums to encapsulate the creation logic for different types of objects. Each enum constant can override an abstract factory method to create a particular instance. This can be especially powerful in scenarios where object creation varies subtly between types. This also bundles object instantiation logic directly with the type identifier.
Unlike external factory classes or numerous conditional checks, this approach keeps creation logic close to the identifier.
The enum not only identifies the type of object but also contains the logic to instantiate it. This centralizes object-creation logic in a tidy, type-safe way.
Enum-Based State Machine
Enums are a natural fit for representing states. You can encode state-specific behavior and transitions within each constant, leading to a self-contained state machine implementation.
Rather than managing states with external variables and conditional logic, each state “knows” what to do.
When to Use It:
When modeling a system with a fixed set of states and clear transitions (e.g., a traffic light or workflow).
When state-specific behavior should be encapsulated with the state itself.
Consider a simple example of a traffic light:
Each state (light color) knows its own behavior and the next state. The state machine logic is completely encapsulated within the enum, making the code both elegant and easy to follow.
Enum for Configurable Validators
Sometimes you need multiple validation strategies for different inputs. You can use enums to encapsulate these strategies, letting each constant implement a validator interface method. This is similar in spirit to the strategy pattern but keeps all the strategies together.
By encapsulating validation logic within an enum, you get a neat, centralized collection of validators that are easy to extend and maintain. Each validator is self-contained, and switching between them is as simple as referencing a different enum constant.
These five enum-based patterns are a great alternative to traditional coding in Java.
Instead of dealing with bulky if-else or switch-case statements, they keep the logic clean and organized within enums, making your code easier to read and less error-prone.
Hope you find them helpful!