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 create a flexible reward‑distribution system, providing detailed code examples, usage guidelines, and best‑practice considerations for each pattern.
Design patterns, when applied correctly, make code simpler and more extensible; this article demonstrates how to use the Strategy, Factory Method, and Builder patterns in Spring through a reward‑distribution example.
1. Strategy Pattern – The pattern is illustrated by defining a PrizeSender interface with support() and sendPrize() methods, then providing three concrete implementations ( PointSender , VirtualCurrencySender , CashSender ) that handle different prize types.
public interface PrizeSender {
/** 判断当前实例是否支持当前奖励的发放 */
boolean support(SendPrizeRequest request);
/** 发放奖励 */
void sendPrize(SendPrizeRequest request);
} // 积分发放
@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("发放积分");
}
} // 虚拟币发放
@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("发放虚拟币");
}
} // 现金发放
@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("发放现金");
}
}Key points: annotate implementations with @Component , provide a boolean support() method to decide applicability, keep business logic in sendPrize() , and pass a request object rather than primitive parameters to allow future extensions.
2. Factory Method Pattern – A factory class selects the appropriate PrizeSender based on the request. The factory iterates over all beans of type PrizeSender injected by Spring and returns the first that supports the request.
@Component
public class PrizeSenderFactory {
@Autowired
private List<PrizeSender> prizeSenders;
public PrizeSender getPrizeSender(SendPrizeRequest request) {
for (PrizeSender prizeSender : prizeSenders) {
if (prizeSender.support(request)) {
return prizeSender;
}
}
throw new UnsupportedOperationException("unsupported request: " + request);
}
}The client obtains a PrizeSender from the factory and calls sendPrize() , decoupling the caller from concrete implementations. Adding a new prize type only requires a new PrizeSender bean.
@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 article shows a Spring‑managed builder for constructing SendPrizeRequest . The inner static Builder class is annotated with @Component and @Scope("prototype") so each request gets a fresh builder instance that can have state.
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
}The builder is obtained from the Spring ApplicationContext to ensure a new prototype instance each time.
@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 Builder newPrizeSendRequestBuilder() {
return context.getBean(Builder.class);
}
}The article concludes that using these three patterns together yields a clean, extensible reward‑distribution module where new prize types can be added without modifying existing business logic.
Architecture Digest
Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.
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.