Friday, January 20, 2023

Strategy Design Pattern in Java using Enum - Tutorial Example

Hello guys, how are you doing? I hope you all are fine and doing good in your life and career. Today, I am going to talk about the Strategy pattern, one of the useful design and coding pattern which will help you to write flexible code. The code which can withstand the test of time in Production. I'll also teach you how you can use Enum to implement the Strategy design pattern and Open Closed design principle better in Java. I have said this before that Java Enum is very versatile and can do a lot more than you normally expect from it. We have seen a lot of examples of Enum in my earlier posts like writing thread-safe Singleton using Enum and 10 ways to use Enum in Java.

In this article, we will learn a new way to use Enum, for implementing the Strategy design pattern. Strategy pattern is one of the famous pattern, which takes advantage of polymorphism, to remove switch cases and strive for the open-closed design principle.

Formally it encapsulates related algorithm, known as strategy and make them interchangeable. So your Client, also known as Context, can use a different algorithm or strategy, without any modification.

One of the key advantages of Strategy pattern is it's extensibility, like introducing a new Strategy is as easy as writing a new class and implementing Strategy interface, with Enum, instead of creating a separate class, you create a separate Enum instance, which means less number of classes and full benefit if Strategy pattern.

Btw, if you are new into the world of design pattern then I suggest you learn more of them. They not only help you to solve common coding problems but also helps you to write better and flexible code. If you want some help in learning them, Java Design Patterns - The Complete Masterclass can be used as a companion. It's one of the better courses on Udemy on this topic.





UML diagram of the Strategy Design Pattern

Here is the UML diagram of the Strategy pattern in Java, Why you should draw the UML diagram? because this is the best way to remember and understand how a design pattern works. In fact, this is the standard way to communicate your design to your fellow developers and team members.

In this diagram, I have explained the strategy design pattern using sorting algorithms like Bubble SortQuickSortInsertion Sort, and Merge Sort. For our code example, you can replace Strategy interface with Match, and sorting strategy to T20, OneDay, and Test Matches.

The UML diagram clearly highlights the relationship between classes and the Strategy interface. You can see the Strategy interface has many implementations and they are swapped on Context class depending upon which kind of sorting you need.

You can further see  Java Design Patterns - The Complete Masterclass course on Udemy to learn more about the Strategy design pattern in Java and also for modern implementation of classic object-oriented patterns.








How to implement a Strategy pattern using Enum in Java

In this tutorial, we will see an example of implementing a Strategy pattern using Java Enum, I would use a sporting example. If you are a cricket fan, like me, you are going to connect with this article, but if you are a Soccer or Tennis fan than let me explain a bit about the example.

In Cricket, there are three popular formats T20 (20 over match), One day(50 over match), and Test(5 days match). If a player, plays all three formats, he needs to adjust its batting strategy to be effective.

For example, T20 is all about scoring quickly, while One-day international games give a bit of time for setting and then scoring. In contrast to the shorter version, the Test match is all about grinding i.e. occupying the crease and making sure your opponent gets tired, before scoring briskly.

In our Strategy pattern example, we have used an Enum to define different batting strategy. We have defined a default play() method and since Enum can override methods, we are overriding it on every instance like on T20, ONE_DAY, and TEST.

Our context class, which is named as Player also has a play() method, which delegates to play() method of configurable Strategy.  Btw, if you are not familiar with Enum in Java and it's essential features like overriding methods, I suggest you join The Complete Java Masterclass course on Udemy. It's one of the most up-to-date courses to learn Java and recently updated to cover the latest Java version as well.

Strategy Design Pattern in Java using Enum - Tutorial Example




Strategy Pattern Example using Enum

Here is a full code example of implementing a Strategy design pattern using Enum in Java. If you are coding in Eclipse IDE then you don't need to do much, just select and copy this code, select the Java project you are working in Eclipse IDE and paste it.

Eclipse IDE will take care of creating the right packages and source files with a proper name like the name of a pa public class.

This is the quickest way to try and execute Java code snippets from the internet in your IDE. Also remember, the Strategy pattern is a good example of the Open Closed Design Principle of SOLID object-oriented design principles coined by Uncle Bob in his classic Clean Codebook.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Java program to demonstrate that Enum can be used to implement Strategy
 * Pattern in Java.
 *
 * @author Javin
 */
public class Match {

    private static final Logger logger = LoggerFactory.getLogger(Match.class);

    public static void main(String args[]) {
       
        Player ctx = new Player(Strategy.T20);
        ctx.play();
       
        ctx.setStrategy(Strategy.ONE_DAY);
        ctx.play();
       
        ctx.setStrategy(Strategy.TEST);
        ctx.play();
   
    }

  
}

/*
 * Player class, which uses different Strategy implementation.
 */
class Player{
    private Strategy battingStrategy;
   
    public Player(Strategy battingStrategy){
        this.battingStrategy = battingStrategy;
    }
   
    public void setStrategy(Strategy newStrategy){
        this.battingStrategy = newStrategy;
    }
   
    public void play(){
        battingStrategy.play();
    }
}

/*
 * An Enum to implement Strategy design pattern in Java. Different instances of
 * Enum represent different batting strategy, based upon type of game e.g. T20,
 * One day international or Test match.
 */
enum Strategy {

    /* Make sure to score quickly on T20 games */
    T20 {

        @Override
        public void play() {
            System.out.printf("In %s, If it's in the V, make sure it goes to tree %n",
                             name());
        }
    },
   
    /* Make a balance between attach and defence in One day */
    ONE_DAY {

        @Override
        public void play() {
            System.out.printf("In %s, Push it for Single %n", name());
        }
    },
   
    /* Test match is all about occupying the crease and grinding opposition */
    TEST {

        @Override
        public void play() {
            System.out.printf("In %s, Grind them hard %n", name());
        }
    };

    public void play() {
        System.out.printf("In Cricket, Play as per Merit of Ball %n");
    }
}

Output:
In T20, If it's in the V, make sure it goes to tree
In ONE_DAY, Push it for Single
In TEST, Grind them hard


That's all on How to Implement the Strategy design pattern in Java using Enum. You can see that it's a lot easier to implement Strategy pattern with Enum, you not only reduced the number of classes but also achieves extensibility and flexibility of Strategy pattern. On the downside, Yes, you need to change your tried and tested Enum every time, though by inserting only new code, it still violates Open Closed principle a bit, which advocates that new functionality should be added by writing new code, rather than modifying existing code.


Further Learning
Design Pattern Library
From 0 to 1: Design Patterns - 24 That Matter - In Java
Java Design Patterns - The Complete Masterclass


If you like this article and interested in learning more about design patterns and principles, you may like following ones as well :
  • 5 Free Courses to learn Object Oriented Programming (courses)
  • 10 Object-Oriented Design Principle Every Programmer Should know (principles)
  • How to implement the Builder design pattern in Java? (solution)
  • 5 Reasons to use Composition in place of Inheritance in Java? (answer)
  • What is the Open-Closed design Principle in OOP? (answer)
  • What is the difference between Factory and Abstract Factory Design Patterns? (answer)
  • What is the difference between State and Strategy patterns in Java? (answer)
  • How to implement the Strategy Design Pattern using Java Enum? (solution)
  • Why implementing Singleton using Enum is better than Class in Java? (answer)
  • Top 5 Books to Learn Design Patterns and Principles (books)
  • How to implement DAO design Pattern in Java? (answer)
  • What is the difference between Association, Aggregation, and Composition in OOP? (answer)
  • What is the difference between Singleton and Static Class in Java? (answer)
  • Why should you Interface for Coding in Java? (answer)
  • A real-life example of the Decorator Pattern in Java? (example)
  • What is the difference between Adapter, Decorator, and Proxy design patterns? (answer)
  • 5 Online Courses to learn Design Pattern in Java (courses)
Thanks for reading this article so far. If you like this article about the Factory design pattern and Dependency Injection pattern in Java then please share it with your friends and colleagues. If you have any questions or feedback then please drop a note.

P. S. - If you are looking for some free course to start learning design patterns, there is a good one on Udemy called Java Design Patterns and Architecture by John Purcell. It doesn't cover all the GOF patterns but still, it's good to learn all the important ones and architectures like MVC.

5 comments :

Anonymous said...

Don't you think with this approach we are going back to if-else way. The whole purpose of Strategy pattern is to not to touch existing class and add new class (Open for extension closed for modification). With this approach we are essentially back to modifying the same class, each time I need to add extra behaviour.

javin paul said...

@Anonymous, you are right, it does violate the open closed design principle, because if you would like to add a new strategy let's say for 10 over match, you have to modify existing class i.e. the enum itself. So in true sense it's not really the GOF Strategy pattern, which allowed you to add new strategy without modifying existing, already tested class. This is specifically good on cases where Strategy are close related to each other and known in advance e.g. various compression strategy, various comparison strategy.

Unknown said...

@gusAbove: The only problem are enums residing in a single compilation unit. You edit this file, true, but no need of messing in other enum instances. Lets be honest: have you ever added new class to the project code without recompiling whole module/project? Player class doesn't change -and this is what's most important - from the client's perspective nothing changes here. Besides, making strategies enums prohibits bad - smelling extending of strategies, which is excellent. I think the overall idea is worth considering.

Anonymous said...

@Jan nowak, this still voilates open closed principle, which is the main aim of using Strategy pattern. Though its good solution in some cases but we cannot call it strategy pattern.

Flamming_Python said...

Easy to make this compatible with the Open-Close Principle really.

Just ensure that the concrete Enum implements an interface; e.g. BattingStrategy; and rename the Enum to e.g. DefaultBattingStrategies

Then change the constructor of the Player class and the setStrategy methods to take the BattingStrategy interface.

That way, there is no need to modify the Enum code at all when a new batting strategy implementation is warranted; the client can simply supply a new BattingStrategy implementation of their own, or a new Enum class which extends BattingStrategy can be created in the same package by the original developer, e.g. ExtraBattingStrategies, and with the same access permissions as DefaultBattingStrategies

Post a Comment