The Strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from the clients that use it.

This pattern is particularly useful when you have an object that needs to be able to execute a single behavior in different ways at different times.

In enterprise applications, you will often have objects that use multiple algorithms to implement some business requirements.

A common example is a number sorting class that supports multiple sorting algorithms, such as bubble sort, merge sort, and quick sort.

Similarly, a file compression class can support different compression algorithm, such as ZIP, GZIP, LZ4, or even a custom compression algorithm.

Another example can be a data encryption class that encrypts data using different encryption algorithms, such as AES, TripleDES, and Blowfish.

Typically, programmers tend to bundle all the algorithm logic in the host class, resulting in a monolithic class with multiple switch case or conditional statements. 

Combination of ComparatorComparable, and Collections.sort() method are one of the best real world example of Strategy design pattern.

In Java, a strategy is usually implemented by creating a hierarchy of classes that extend from a base interface known as Strategy.

The intent of State pattern is to facilitate state transition while the intent of Strategy pattern is to change the behavior of a class by changing internal algorithm at run-time without modifying the class itself.

Example-1

Strategy Design Pattern Implementation in Java
UML diagram of Strategy pattern 

interface Strategy {
    public void sort(int[] numbers);
}

class BubbleSort implements Strategy {

    @Override
    public void sort(int[] numbers) {
        System.out.println("sorting array using bubble sort strategy");
   }
}

class InsertionSort implements Strategy {

    @Override
    public void sort(int[] numbers) {
        System.out.println("sorting array using insertion sort strategy");
    }
}

class QuickSort implements Strategy {

    @Override
    public void sort(int[] numbers) {
        System.out.println("sorting array using quick sort strategy");
    }
}

class MergeSort implements Strategy {

    @Override
    public void sort(int[] numbers) {
        System.out.println("sorting array using merge sort strategy");
    }
}

class Context {

    private final Strategy strategy;

    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    public void arrange(int[] input) {
        strategy.sort(input);
    }
}

/**
 * Java Program to implement Strategy design pattern in Java. 
 * Strategy pattern allows you to supply different strategy without
 * changing the Context class, which uses that strategy. You can
 * also introduce new sorting strategy any time. Similar example
 * is Collections.sort() method, which accept Comparator or Comparable
 * which is actually a Strategy to compare objects in Java.
 * 
 * @author WINDOWS 8
 */

public class Test {

    public static void main(String args[]) throws InterruptedException {
        
        // we can provide any strategy to do the sorting 
        int[] var = {1, 2, 3, 4, 5 };
        Context ctx = new Context(new BubbleSort());
        ctx.arrange(var);
        
        // we can change the strategy without changing Context class
        ctx = new Context(new QuickSort());
        ctx.arrange(var);
    }

}

Output
sorting array using bubble sort strategy
sorting array using quick sort strategy

Example-2

  • Strategy (EncryptionStrategy): Is an interface common to all supported algorithm-specific classes.
  • ConcreteStrategy (AesEncryptionStrategy and BlowfishEncryptionStrategy): Implements the algorithm using the Strategy interface.
  • Context (Encryptor): Provides the interface to client for encrypting data. The Context maintains a reference to a Strategy object and is instantiated and initialized by clients with a ConcreteStrategy object.

public interface EncryptionStrategy {
    void encryptData(String plainText);
}

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;

public class AesEncryptionStrategy implements EncryptionStrategy{

   @Override
    public void encryptData(String plaintext) {
    System.out.println("-------Encrypting data using AES algorithm-------");
       try {
           KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
           keyGenerator.init(128);
           SecretKey secretKey = keyGenerator.generateKey();
           byte[] plaintTextByteArray = plaintext.getBytes("UTF8");

           Cipher cipher = Cipher.getInstance("AES");
           cipher.init(Cipher.ENCRYPT_MODE, secretKey);
           byte[] cipherText = cipher.doFinal(plaintTextByteArray);

           System.out.println("Original data: " + plaintext);
           System.out.println("Encrypted data:");
           for (int i = 0; i < cipherText.length; i++) {
               System.out.print(cipherText[i] + " ");
           }
       }
           catch(Exception ex){
               ex.printStackTrace();
           }
       }
   }

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;

public class BlowfishEncryptionStrategy implements EncryptionStrategy{
    @Override
    public void encryptData(String plaintext) {
        System.out.println("\n---Encrypting data using Blowfish algorithm");
        try {
           KeyGenerator keyGenerator = KeyGenerator.getInstance("Blowfish");
            keyGenerator.init(128);
            SecretKey secretKey = keyGenerator.generateKey();
            byte[] plaintTextByteArray = plaintext.getBytes("UTF8");

            Cipher cipher = Cipher.getInstance("Blowfish");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            byte[] cipherText = cipher.doFinal(plaintTextByteArray);

            System.out.println("Original data: " + plaintext);
            System.out.println("Encrypted data:");
            for (int i = 0; i < cipherText.length; i++) {
                System.out.print(cipherText[i] + " ");
            }
        }
        catch(Exception ex){
            ex.printStackTrace();
        }
    }
}

public class Encryptor {
    
private EncryptionStrategy strategy;
    private String plainText;
    
   public Encryptor(EncryptionStrategy strategy){
        this.strategy=strategy;
    }

    public void encrypt(){
        strategy.encryptData(plainText);
    }

    public String getPlainText() {
        return plainText;
    }

    public void setPlainText(String plainText) {
        this.plainText = plainText;
    }
}

import static org.junit.Assert.*;


public class EncryptorTest {

    @Test
    public void testEncrypt() throws Exception {
      EncryptionStrategy aesStrategy=new AesEncryptionStrategy();
      Encryptor aesEncryptor=new Encryptor(aesStrategy);
      aesEncryptor.setPlainText("This is plain text");
      aesEncryptor.encrypt();

       EncryptionStrategy blowfishStrategy=new BlowfishEncryptionStrategy();
        Encryptor blowfishEncryptor=new Encryptor(blowfishStrategy);
        blowfishEncryptor.setPlainText("This is plain text");
        blowfishEncryptor.encrypt();
    }
}

Test Result

------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running guru.springframework.gof.strategy.context.EncryptorTest
-------Encrypting data using AES algorithm-------
Original data: This is plain text
Encrypted data:
97 11 54 73 -21 92 109 -124 -120 110 -43 20 123 99 87 120 120 95 70 -63 -8 70 41 44 -73 -94 48 127 61 43 -96 110 
-------Encrypting data using Blowfish algorithm-------
Original data: This is plain text
Encrypted data:
3 -34 -23 -74 -61 -55 99 -114 71 -113 124 -57 -65 -45 -128 37 -123 -83 118 107 42 -123 84 14 
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 7.72 sec - in guru.springframework.gof.strategy.context.EncryptorTest

Things to Remember

Now let’s revise what you have learn in this tutorial about strategy design pattern  :

1) This pattern defines a set of related algorithm and encapsulate them in separated classes, and allows client to choose any algorithm at run time.

2) It allows to add new algorithm without modifying existing algorithms or context class, which uses algorithm or strategies.

3) Strategy is a behavioral pattern in GOF list.

4) Strategy pattern is based upon Open Closed design principle of SOLID Principles of Object Oriented Design.

5) Collections.sort() and Comparator interface is real world example of Strategy pattern.