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.

Architecture Digest
Architecture Digest
Architecture Digest
Applying Strategy, Factory Method, and Builder Patterns in Spring for Reward Distribution

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 {<br/><br/>  /** 判断当前实例是否支持当前奖励的发放 */<br/>  boolean support(SendPrizeRequest request);<br/><br/>  /** 发放奖励 */<br/>  void sendPrize(SendPrizeRequest request);<br/>}<br/>
// 积分发放<br/>@Component<br/>public class PointSender implements PrizeSender {<br/><br/>  @Override<br/>  public boolean support(SendPrizeRequest request) {<br/>    return request.getPrizeType() == PrizeTypeEnum.POINT;<br/>  }<br/><br/>  @Override<br/>  public void sendPrize(SendPrizeRequest request) {<br/>    System.out.println("发放积分");<br/>  }<br/>}<br/>
// 虚拟币发放<br/>@Component<br/>public class VirtualCurrencySender implements PrizeSender {<br/><br/>  @Override<br/>  public boolean support(SendPrizeRequest request) {<br/>    return PrizeTypeEnum.VIRTUAL_CURRENCY == request.getPrizeType();<br/>  }<br/><br/>  @Override<br/>  public void sendPrize(SendPrizeRequest request) {<br/>    System.out.println("发放虚拟币");<br/>  }<br/>}<br/>
// 现金发放<br/>@Component<br/>public class CashSender implements PrizeSender {<br/><br/>  @Override<br/>  public boolean support(SendPrizeRequest request) {<br/>    return PrizeTypeEnum.CASH == request.getPrizeType();<br/>  }<br/><br/>  @Override<br/>  public void sendPrize(SendPrizeRequest request) {<br/>    System.out.println("发放现金");<br/>  }<br/>}<br/>

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<br/>public class PrizeSenderFactory {<br/><br/>  @Autowired<br/>  private List<PrizeSender> prizeSenders;<br/><br/>  public PrizeSender getPrizeSender(SendPrizeRequest request) {<br/>    for (PrizeSender prizeSender : prizeSenders) {<br/>      if (prizeSender.support(request)) {<br/>        return prizeSender;<br/>      }<br/>    }<br/>    throw new UnsupportedOperationException("unsupported request: " + request);<br/>  }<br/>}<br/>

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<br/>public class ApplicationService {<br/><br/>  @Autowired<br/>  private PrizeSenderFactory prizeSenderFactory;<br/><br/>  public void mockedClient() {<br/>    SendPrizeRequest request = new SendPrizeRequest();<br/>    request.setPrizeType(PrizeTypeEnum.POINT);<br/>    PrizeSender prizeSender = prizeSenderFactory.getPrizeSender(request);<br/>    prizeSender.sendPrize(request);<br/>  }<br/>}<br/>

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 {<br/><br/>  private final PrizeTypeEnum prizeType;<br/>  private final int amount;<br/>  private final String userId;<br/><br/>  public SendPrizeRequest(PrizeTypeEnum prizeType, int amount, String userId) {<br/>    this.prizeType = prizeType;<br/>    this.amount = amount;<br/>    this.userId = userId;<br/>  }<br/><br/>  @Component<br/>  @Scope("prototype")<br/>  public static class Builder {<br/><br/>    @Autowired<br/>    PrizeService prizeService;<br/><br/>    private int prizeId;<br/>    private String userId;<br/><br/>    public Builder prizeId(int prizeId) {<br/>      this.prizeId = prizeId;<br/>      return this;<br/>    }<br/><br/>    public Builder userId(String userId) {<br/>      this.userId = userId;<br/>      return this;<br/>    }<br/><br/>    public SendPrizeRequest build() {<br/>      Prize prize = prizeService.findById(prizeId);<br/>      return new SendPrizeRequest(prize.getPrizeType(), prize.getAmount(), userId);<br/>    }<br/>  }<br/><br/>  // getters omitted<br/>}<br/>

The builder is obtained from the Spring ApplicationContext to ensure a new prototype instance each time.

@Service<br/>public class ApplicationService {<br/><br/>  @Autowired<br/>  private PrizeSenderFactory prizeSenderFactory;<br/><br/>  @Autowired<br/>  private ApplicationContext context;<br/><br/>  public void mockedClient() {<br/>    SendPrizeRequest request = newPrizeSendRequestBuilder()<br/>        .prizeId(1)<br/>        .userId("u4352234")<br/>        .build();<br/><br/>    PrizeSender prizeSender = prizeSenderFactory.getPrizeSender(request);<br/>    prizeSender.sendPrize(request);<br/>  }<br/><br/>  public Builder newPrizeSendRequestBuilder() {<br/>    return context.getBean(Builder.class);<br/>  }<br/>}<br/>

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Design PatternsJavaStrategy Patternspringdependency-injectionFactory MethodBuilder Pattern
Architecture Digest
Written by

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.

0 followers
Reader feedback

How this landed with the community

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.