Fundamentals 6 min read

Applying the Strategy Pattern with Simple Factory in a Java Backend Service

This article explains how to use the Strategy pattern combined with a simple factory in a Spring‑based Java backend, showing interface definition, multiple arithmetic strategy implementations, a factory that registers them in a map, a service that selects a strategy at runtime, and a REST controller for testing.

Architect's Guide
Architect's Guide
Architect's Guide
Applying the Strategy Pattern with Simple Factory in a Java Backend Service

Many developers are familiar with the Strategy pattern but may not know how to apply it in real projects; this article demonstrates its use when integrating a third‑party OA system that calls back different business interfaces based on a routing field.

First, a routing interface CalculationStrategy is defined, and concrete strategy classes (addition, division, multiplication, subtraction) implement this interface and are annotated with @Component so Spring can discover them.

public interface CalculationStrategy {
    /**
     * Strategy interface
     */
    int operate(int num1, int num2);
}

@Component("add")
class AddCalculationStrategyImpl implements CalculationStrategy {
    @Override
    public int operate(int num1, int num2) {
        return num1 + num2;
    }
}

@Component("Division")
class DivisionStrategyImpl implements CalculationStrategy {
    @Override
    public int operate(int num1, int num2) {
        return num1 / num2;
    }
}

@Component("multiple")
class MultiplicationStrategyImpl implements CalculationStrategy {
    @Override
    public int operate(int num1, int num2) {
        return num1 * num2;
    }
}

@Component("subtract")
class SubtractionStrategyImpl implements CalculationStrategy {
    @Override
    public int operate(int num1, int num2) {
        return num1 - num2;
    }
}

@Component
class TestStrategyImpl implements CalculationStrategy {
    @Override
    public int operate(int num1, int num2) {
        return num1 - num2;
    }
}

The second step is a factory (treated as a strategy context) that collects all @Component beans implementing CalculationStrategy and stores them in a Map<String, CalculationStrategy> for quick lookup.

@Component
public class CalculationFactory {
    /**
     * Put strategy key (bean name) and implementation into the map.
     */
    public final Map
calculationStrategyMap = Maps.newHashMapWithExpectedSize(4);

    /**
     * Register all strategies at startup via constructor injection.
     */
    public CalculationFactory(Map
strategyMap) {
        this.calculationStrategyMap.clear();
        this.calculationStrategyMap.putAll(strategyMap);
    }

    // Getter for service layer
    public Map
getCalculationStrategyMap() {
        return calculationStrategyMap;
    }
}

Third, a service uses the factory to retrieve the appropriate strategy based on the incoming strategy string and executes the operate method.

@Service
public class CalculationService {
    @Autowired
    private CalculationFactory calculationFactory;

    public int operateByStrategy(String strategy, int num1, int num2) {
        // Potential null handling for missing strategy
        return calculationFactory.getCalculationStrategyMap().get(strategy).operate(num1, num2);
    }
}

Finally, a simple REST controller exposes an endpoint for testing the strategies, allowing callers to specify the operation name and two integers.

@RestController
@RequestMapping("/strategy")
public class TestStrategyController {
    @Autowired
    private CalculationService calculationService;

    @GetMapping("/test/{operation}/{num1}/{num2}")
    public int testCalculation(@PathVariable String operation, @PathVariable int num1, @PathVariable int num2) {
        // Parameter validation omitted for brevity
        return calculationService.operateByStrategy(operation, num1, num2);
    }
}

The main advantage of this design is extensibility: adding a new business branch only requires creating a new strategy implementation and annotating it with @Component ; no other code changes are needed, making the system easy to maintain and evolve.

backendDesign PatternsJavaStrategy PatternSpringDependency InjectionFactory
Architect's Guide
Written by

Architect's Guide

Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.

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.