Applying Strategy, Factory Method, and Builder Patterns in Spring for Reward Distribution
This article explains how to implement the Strategy, Factory Method, and Builder design patterns within a Spring application to decouple reward‑distribution logic, showing interface definitions, concrete implementations, a factory for dynamic bean selection, and a prototype‑scoped builder for request construction.
Design patterns such as Strategy, Factory Method, and Builder can make Spring‑based code more concise, extensible, and maintainable. The article demonstrates their usage through a reward‑distribution example.
1. Strategy Pattern
The Strategy pattern defines an interface with multiple implementations, each handling a specific case. In the example, public interface PrizeSender { boolean support(SendPrizeRequest request); void sendPrize(SendPrizeRequest request); } is the strategy interface.
Three concrete strategies are provided:
// PointSender implementation
@Component
public class PointSender implements PrizeSender {
@Override
public boolean support(SendPrizeRequest request) {
return request.getPrizeType() == PrizeTypeEnum.POINT;
}
@Override
public void sendPrize(SendPrizeRequest request) {
System.out.println("发放积分");
}
} // VirtualCurrencySender implementation
@Component
public class VirtualCurrencySender implements PrizeSender {
@Override
public boolean support(SendPrizeRequest request) {
return PrizeTypeEnum.VIRTUAL_CURRENCY == request.getPrizeType();
}
@Override
public void sendPrize(SendPrizeRequest request) {
System.out.println("发放虚拟币");
}
} // CashSender implementation
@Component
public class CashSender implements PrizeSender {
@Override
public boolean support(SendPrizeRequest request) {
return PrizeTypeEnum.CASH == request.getPrizeType();
}
@Override
public void sendPrize(SendPrizeRequest request) {
System.out.println("发放现金");
}
}Each implementation declares @Component so Spring manages it as a bean, provides a support() method to decide if it can handle the request, and a sendPrize() method to perform the business logic.
2. Factory Method Pattern
The factory method encapsulates the selection of a concrete strategy. The PrizeSenderFactory scans all PrizeSender beans and returns the first one whose support() returns true.
@Component
public class PrizeSenderFactory {
@Autowired
private List
prizeSenders;
public PrizeSender getPrizeSender(SendPrizeRequest request) {
for (PrizeSender prizeSender : prizeSenders) {
if (prizeSender.support(request)) {
return prizeSender;
}
}
throw new UnsupportedOperationException("unsupported request: " + request);
}
}The factory contains no knowledge of concrete classes, allowing new PrizeSender implementations to be added without modifying existing code.
A client example shows how to obtain a strategy and invoke it:
@Service
public class ApplicationService {
@Autowired
private PrizeSenderFactory prizeSenderFactory;
public void mockedClient() {
SendPrizeRequest request = new SendPrizeRequest();
request.setPrizeType(PrizeTypeEnum.POINT);
PrizeSender prizeSender = prizeSenderFactory.getPrizeSender(request);
prizeSender.sendPrize(request);
}
}3. Builder Pattern
The Builder pattern is used to construct a complex request object while allowing Spring‑injected dependencies inside the builder. The inner static Builder class is marked with @Component and @Scope("prototype") so each build starts with a fresh instance.
public class SendPrizeRequest {
private final PrizeTypeEnum prizeType;
private final int amount;
private final String userId;
public SendPrizeRequest(PrizeTypeEnum prizeType, int amount, String userId) {
this.prizeType = prizeType;
this.amount = amount;
this.userId = userId;
}
@Component
@Scope("prototype")
public static class Builder {
@Autowired
PrizeService prizeService;
private int prizeId;
private String userId;
public Builder prizeId(int prizeId) { this.prizeId = prizeId; return this; }
public Builder userId(String userId) { this.userId = userId; return this; }
public SendPrizeRequest build() {
Prize prize = prizeService.findById(prizeId);
return new SendPrizeRequest(prize.getPrizeType(), prize.getAmount(), userId);
}
}
// getters omitted for brevity
}The client obtains a new builder from the Spring ApplicationContext , sets parameters fluently, and builds the request:
@Service
public class ApplicationService {
@Autowired
private PrizeSenderFactory prizeSenderFactory;
@Autowired
private ApplicationContext context;
public void mockedClient() {
SendPrizeRequest request = newPrizeSendRequestBuilder()
.prizeId(1)
.userId("u4352234")
.build();
PrizeSender prizeSender = prizeSenderFactory.getPrizeSender(request);
prizeSender.sendPrize(request);
}
public SendPrizeRequest.Builder newPrizeSendRequestBuilder() {
return context.getBean(SendPrizeRequest.Builder.class);
}
}4. Summary
The article uses a reward‑distribution scenario to illustrate how Spring can integrate the Strategy, Factory Method, and Builder patterns, highlighting key points such as bean registration with @Component , prototype scope for stateful builders, and decoupling of business logic from client code.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
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.