Backend Development 9 min read

Mastering the Strategy Pattern in Spring Boot: Clean, Extensible Code with Real Examples

This article walks through the concept and practical implementation of the Strategy design pattern in Spring Boot, showing how to define operation interfaces, create concrete strategy classes, use factories and Spring's IoC container for clean, maintainable, and extensible backend code.

macrozheng
macrozheng
macrozheng
Mastering the Strategy Pattern in Spring Boot: Clean, Extensible Code with Real Examples

1. Background Introduction

Strategy design pattern is widely known; using it properly in business development can make code more readable and improve extensibility.

2. Code Practice

First, define an

Operation

interface for calculation logic:

<code>public interface Operation {
    /**
     * Execute calculation
     * @param a operand a
     * @param b operand b
     * @return result
     */
    int execute(int a, int b);
}</code>

Then implement four concrete strategies:

<code>public class AddOperation implements Operation {
    @Override
    public int execute(int a, int b) { return a + b; }
}

public class SubOperation implements Operation {
    @Override
    public int execute(int a, int b) { return a - b; }
}

public class MultiOperation implements Operation {
    @Override
    public int execute(int a, int b) { return a * b; }
}

public class DivOperation implements Operation {
    @Override
    public int execute(int a, int b) { return a / b; }
}</code>

Create a factory to obtain the appropriate implementation based on a string key:

<code>public class OperatorFactory {
    private static Map<String, Operation> operationMap = new HashMap<>();
    static {
        operationMap.put("add", new AddOperation());
        operationMap.put("sub", new SubOperation());
        operationMap.put("multi", new MultiOperation());
        operationMap.put("div", new DivOperation());
        // more operators
    }
    public static Optional<Operation> getOperation(String operator) {
        return Optional.ofNullable(operationMap.get(operator));
    }
}</code>

Usage example:

<code>public class OperatorTestMain {
    public static void main(String[] args) {
        Operation targetOperation = OperatorFactory
                .getOperation("add")
                .orElseThrow(() -> new IllegalArgumentException("Invalid Operator"));
        int result = targetOperation.execute(1, 2);
        System.out.println("result:" + result);
    }
}</code>

3. SpringBoot Practice

3.1 Solution One (Recommended)

Define a

Command

interface to abstract operations:

<code>public interface Command {
    /** Command type identifier */
    String operateType();
    /** Execute operation */
    Integer execute(int a, int b);
}</code>

Implement four command classes:

<code>@Component
public class AddCommand implements Command {
    @Override
    public String operateType() { return "add"; }
    @Override
    public Integer execute(int a, int b) { return a + b; }
}

@Component
public class SubCommand implements Command {
    @Override
    public String operateType() { return "subtract"; }
    @Override
    public Integer execute(int a, int b) { return a - b; }
}

@Component
public class MultiCommand implements Command {
    @Override
    public String operateType() { return "multiply"; }
    @Override
    public Integer execute(int a, int b) { return a * b; }
}

@Component
public class DivCommand implements Command {
    @Override
    public String operateType() { return "divide"; }
    @Override
    public Integer execute(int a, int b) { return a / b; }
}</code>

Create a service that collects all

Command

beans from the Spring IoC container and performs calculations:

<code>@Component
public class CalculatorService implements ApplicationContextAware {
    private Map<String, Command> commandMap = new ConcurrentHashMap<>();

    public int calculate(String operateType, int a, int b) {
        Command targetCommand = Optional.ofNullable(commandMap.get(operateType))
                .orElseThrow(() -> new IllegalArgumentException("Invalid Operator"));
        return targetCommand.execute(a, b);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, Command> tempMap = applicationContext.getBeansOfType(Command.class);
        tempMap.values().forEach(source -> commandMap.put(source.operateType(), source));
    }
}</code>

Test the service:

<code>@RunWith(SpringRunner.class)
@SpringBootTest
public class CalculatorServiceTest {
    @Autowired
    private CalculatorService calculatorService;

    @Test
    public void test() {
        int result = calculatorService.calculate("add", 1, 2);
        System.out.println("result:" + result);
    }
}</code>

3.2 Solution Two (Alternative)

Leverage Spring's automatic injection of all

Command

implementations into a

Map

without writing a dedicated service.

<code>@Component
public class CommandFactory {
    /** Spring injects all Command beans; key is bean name, value is the implementation */
    @Autowired
    private Map<String, Command> commandMap;

    public int calculate(String operateType, int a, int b) {
        Command targetCommand = Optional.ofNullable(commandMap.get(operateType))
                .orElseThrow(() -> new IllegalArgumentException("Invalid Operator"));
        return targetCommand.execute(a, b);
    }
}</code>

Use the factory directly in tests:

<code>@RunWith(SpringRunner.class)
@SpringBootTest
public class CalculatorServiceTest {
    @Autowired
    private CommandFactory commandFactory;

    @Test
    public void test() {
        int result = commandFactory.calculate("addCommand", 1, 2);
        System.out.println("result:" + result);
    }
}</code>

4. Conclusion

The article demonstrates how to introduce the Strategy pattern into a Spring Boot project, showing two practical approaches. Both improve code readability and extensibility, with the second approach taking advantage of Spring's IoC container to automatically wire strategy implementations.

Design PatternsJavastrategy patternbackend developmentSpringBoot
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.