Boosting API Extensibility in SpringBoot with the Strategy Pattern
The article demonstrates how to combine SpringBoot with the Strategy pattern and a simple factory to route different business operations—add, subtract, multiply, divide—through a single API, registering strategy beans in a map for easy extension without modifying existing code.
Many developers are familiar with the Strategy pattern but may not know how it can be applied in a real project to improve interface extensibility. The author presents a scenario where a system must handle callbacks from a third‑party OA platform, routing each callback to a specific business branch based on a field.
Instead of creating multiple endpoints or using a long if…else chain, the solution combines the Strategy pattern with a simple factory. First, a CalculationStrategy interface is defined, and four concrete implementations—addition, division, multiplication, and subtraction—are annotated with @Component and given distinct bean names.
public interface CalculationStrategy {
/**
* 策略接口
*/
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;
}
}
/** If Component annotation does not specify a name, the default bean name is the camel‑case class name */
@Component
class TestStrategyImpl implements CalculationStrategy {
@Override
public int operate(int num1, int num2) {
return num1 - num2;
}
}The next step is a factory that acts as a strategy registry. During application startup, Spring injects all beans that implement CalculationStrategy into a Map<String, CalculationStrategy>. The factory stores this map in a static‑like field using Guava's Maps.newHashMapWithExpectedSize, allowing fast lookup by bean name.
public class CalculationFactory {
/** Put strategy key and instance into map */
public final Map<String, CalculationStrategy> calculationStrategyMap = Maps.newHashMapWithExpectedSize(4);
/** Register strategies at startup via constructor */
public CalculationFactory(Map<String, CalculationStrategy> strategyMap) {
this.calculationStrategyMap.clear();
this.calculationStrategyMap.putAll(strategyMap);
}
// Getter for service layer
public Map<String, CalculationStrategy> getCalculationStrategyMap() {
return calculationStrategyMap;
}
}A service class retrieves the appropriate strategy from the factory based on the incoming strategy parameter and invokes its operate method. The author notes that map.get() may return null, so callers should add their own null‑handling logic.
@Service
public class CalculationService {
@Autowired
private CalculationFactory calculationFactory;
public int operateByStrategy(String strategy, int num1, int num2) {
// May need null check for map.get()
return calculationFactory.getCalculationStrategyMap().get(strategy).operate(num1, num2);
}
}Finally, a REST controller exposes a test endpoint that forwards the request to the service. The endpoint URL follows the pattern /strategy/test/{operation}/{num1}/{num2}, allowing callers to specify the desired operation directly.
@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) {
// omit parameter null checks
return calculationService.operateByStrategy(operation, num1, num2);
}
}Running the example produces the expected arithmetic results, as shown in the accompanying screenshot.
The main advantage of this design is that adding a new business branch only requires creating a new implementation of CalculationStrategy and annotating it with @Component. No other code changes are needed, which simplifies future extensions and keeps the system maintainable.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architect's Guide
Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
