Strategy Design Pattern

Strategy design pattern is behavioral design pattern where we choose a specific implementation of algorithm or task in run time – out of multiple other implementations for same task.

The important point is that these implementations are interchangeable – based on task a implementation may be picked without disturbing the application workflow.

Table of Contents
Introduction
Design Participants
Problem Statement
Solution with strategy design pattern
Code Implementation
Demo
Popular Implementations
Summary

Introduction

Strategy pattern involves removing an algorithm from its host class and putting it in separate class so that in the same programming context there might be different algorithms (i.e. strategies), which can be selected in runtime.

Strategy pattern enables a client code to choose from a family of related but different algorithms and gives it a simple way to choose any of the algorithm in runtime depending on the client context.

Driven by Open/closed Principle

This pattern is based on Open/closed principle. We don’t need to modify the context [closed for modification], but can choose and add any implementation [open for extension].

For example, in Collections.sort() – we don’t need to change the sort method to achieve different sorting results. We can just supply different comparators in runtime.

Read More: Comparator Example

Design Participants

In Strategy pattern, we first create an abstraction of algorithm. This is an interface having the abstract operation. Then we create implementations of this abstraction and these are called strategies.

A client will always call the abstraction, and will pass a context object. This context object will decide which strategy to use.

Strategy Pattern Participants
Strategy Pattern Participants

Problem Statement

Let’s solve a design problem to understand strategy pattern in more detail.

I want to design a social media application which allows me to connect to my friends on all four social platforms i.e. Facebook, Google Plus, Twitter and Orkut (for example sake). Now I want that client should be able to tell the name of friend and desired platform – then my application should connect to him transparently.

More importantly, if I want to add more social platforms into application then application code should accommodate it without breaking the design.

Solution with strategy design pattern

In above problem, we have an operation which can be done in multiple ways (connect to friend) and user can choose desired way on runtime. So it’s good candidate for strategy design pattern.

To implement the solution, let’s design one participant one at a time.

  • ISocialMediaStrategy – The interface which abstract the operation.
  • SocialMediaContext – The context which determines the implementation.
  • Implementations – Various implementations of ISocialMediaStrategy. E.g. FacebookStrategy, GooglePlusStrategy, TwitterStrategy and OrkutStrategy.

Class Diagram

Strategy Pattern Class Diagram
Strategy Pattern Class Diagram

Code Implementation

Now let’s code above design participants.

ISocialMediaStrategy.java

package com.howtodoinjava.designpattern.strategy;

public interface ISocialMediaStrategy 
{
	public void connectTo(String friendName);
}

SocialMediaContext.java

package com.howtodoinjava.designpattern.strategy;

public class SocialMediaContext 
{
	ISocialMediaStrategy smStrategy;

	public void setSocialmediaStrategy(ISocialMediaStrategy smStrategy) 
	{
		this.smStrategy = smStrategy;
	}

	public void connect(String name) 
	{
		smStrategy.connectTo(name);
	}
}

FacebookStrategy.java

package com.howtodoinjava.designpattern.strategy.impl;

import com.howtodoinjava.designpattern.strategy.ISocialMediaStrategy;

public class FacebookStrategy implements ISocialMediaStrategy {

	public void connectTo(String friendName) 
	{
		System.out.println("Connecting with " + friendName + " through Facebook");
	}
}

GooglePlusStrategy.java

package com.howtodoinjava.designpattern.strategy.impl;

import com.howtodoinjava.designpattern.strategy.ISocialMediaStrategy;

public class GooglePlusStrategy implements ISocialMediaStrategy {

	public void connectTo(String friendName) 
	{
		System.out.println("Connecting with " + friendName + " through GooglePlus");
	}
}

TwitterStrategy.java

package com.howtodoinjava.designpattern.strategy.impl;

import com.howtodoinjava.designpattern.strategy.ISocialMediaStrategy;

public class TwitterStrategy implements ISocialMediaStrategy {

	public void connectTo(String friendName) 
	{
		System.out.println("Connecting with " + friendName + " through Twitter");
	}
}

OrkutStrategy.java

package com.howtodoinjava.designpattern.strategy.impl;

import com.howtodoinjava.designpattern.strategy.ISocialMediaStrategy;

public class OrkutStrategy implements ISocialMediaStrategy {

	public void connectTo(String friendName) 
	{
		System.out.println("Connecting with " + friendName + " through Orkut [not possible though :)]");
	}
}

Demo

Now see how these strategies can be used in runtime.

package com.howtodoinjava.designpattern.strategy.demo;

import com.howtodoinjava.designpattern.strategy.SocialMediaContext;
import com.howtodoinjava.designpattern.strategy.impl.FacebookStrategy;
import com.howtodoinjava.designpattern.strategy.impl.GooglePlusStrategy;
import com.howtodoinjava.designpattern.strategy.impl.OrkutStrategy;
import com.howtodoinjava.designpattern.strategy.impl.TwitterStrategy;

public class Demo {
	public static void main(String[] args) {

		// Creating social Media Connect Object for connecting with friend by
		// any social media strategy.
		SocialMediaContext context = new SocialMediaContext();

		// Setting Facebook strategy.
		context.setSocialmediaStrategy(new FacebookStrategy());
		context.connect("Lokesh");

		System.out.println("====================");

		// Setting Twitter strategy.
		context.setSocialmediaStrategy(new TwitterStrategy());
		context.connect("Lokesh");

		System.out.println("====================");

		// Setting GooglePlus strategy.
		context.setSocialmediaStrategy(new GooglePlusStrategy());
		context.connect("Lokesh");

		System.out.println("====================");

		// Setting Orkut strategy.
		context.setSocialmediaStrategy(new OrkutStrategy());
		context.connect("Lokesh");
	}
}

Output:

Connecting with Lokesh through Facebook
====================
Connecting with Lokesh through Twitter
====================
Connecting with Lokesh through GooglePlus
====================
Connecting with Lokesh through Orkut [not possible though :)]

Popular Implementations

  1. Java Collections.sort(list, comparator) method where client actually passes suitable comparator based on the requirement in runtime to the method and the method is generic to accept any comparator type. Based on the comparator being passed, same collection can be sorted differently.
  2. Appenders, Layouts and Filters in Log4j.
  3. Layout Managers in UI toolkits.

Summary

  • This pattern defines a set of related algorithm and encapsulate them in separated classes, and allows client to choose any algorithm at run time.
  • It allows to add new algorithm without modifying existing algorithms or context class, which uses algorithm or strategies
  • Strategy is a behavioral pattern in Gang of Four Design pattern list.
  • Strategy pattern is based upon Open Closed design principle of SOLID principals.
  • Combination of Collections.sort() and Comparator interface is an solid example of Strategy pattern.

That’s all about strategy design pattern. Drop me your questions in comments section.

Happy Learning !!

Leave a Comment

  1. Hi Sir,

    I have been following your blogs for a long time and these are really very helpful.
    I have just one doubt.
    what is the need of creating context class? because anyway we can simply create the implementation class object(either directly or by using factory pattern) and pass the name of the friend we want to connect with.
    for example :-

    // Setting Facebook strategy.

    SocialmediaStrategy facebookStrategy= SocialmediaStrategyFactory.getBean(“facebook”);

    facebookStrategy.connectTo(“Lokesh”);

    ============================
    SocialmediaStrategy twitterStrategy= SocialmediaStrategyFactory.getBean(“twitter”);

    twitterStrategy.connectTo(“Lokesh”);

    Thanks.

    Reply
    • Good question. Yes, we can write the code using the factory pattern as well because a factory is also used to create classes having similar features.

      The context class just neatly provides the abstraction that you will appreciate once you use dependency injection for setting various strategies.

      Reply
  2. Thanks for the explanation. I built a similar solution for 2 implementation strategies of connecting to HTTP or S FTP . Do you think, this is a slightly better way of implementing Strategy Design pattern? The code that I wrote would not require the user to know about the name of the Implementation class. In the future if another implementation class gets added, the user would need not know the name of the class.
    Here goes my code:

    1. Strategy Interface

    public interface IConnectionStrategy {
    
    	/**Get Implementation type*/
    	public boolean getTypeOfConnectionStrategy(String type);	
    
    	/**	concrete method to test connection */
    	public boolean testConnection();
    }
    
    

    2. Implementation 1 : HTTP

    public class HTTPConnectionStrategy implements IConnectionStrategy {
    	@Override
    	public boolean testConnection() {
    		// establish connection code goes here
    		return true;
    	}
    	@Override
    	public boolean getTypeOfConnectionStrategy(String type) {
    		return (type.equals("HTTP"));
    	}
    }
    

    2. Implementation 2: SFTP

    public class SFTPConnectionStrategy implements IConnectionStrategy {
    	@Override
    	public boolean testConnection() {
    		// establish connection code goes here
    		return true;
    	}
    	@Override
    	public boolean getTypeOfConnectionStrategy(String type) {
    		return (type.equals("SFTP"));
    	}
    }
    

    3. Strategy Context class

    /**
     *Strategy Context to determine strategy at run time */
    public class StrategyContext {
    	//externally initialized
    	List<IConnectionStrategy> connexonStrategies;
    	/**Test the connection based on type*/
    	public boolean testConnection(String argType) {
    		boolean isTestSuccessful=false;
    		for (IConnectionStrategy iConnectionStrategy : connexonStrategies) {
    			if(iConnectionStrategy.getTypeOfConnectionStrategy(argType)) {
    				isTestSuccessful =  iConnectionStrategy.testConnection();
    			}
    		}
    		return isTestSuccessful;
    	}
    }
    
    class TestClass{
    	// Testing Connection
    	public static void main(String[] args) {
    		StrategyContext strategyContext = new StrategyContext();
    		strategyContext.testConnection("SFTP");
    	}
    }
    
    Reply
    • it is not a better implementing because it break the “open-close” principle.once you add a new strategy you have to modify the existing code, for example, you have to add the “argType”.

      Reply

Leave a Comment

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial

Dark Mode

Dark Mode