Eliminate Complex if‑else with Strategy & Factory Patterns in Spring

This article explains how to replace tangled if‑else logic in business code with the Strategy and Factory design patterns, integrates them into a Spring application, and demonstrates the resulting improvements in readability, maintainability, and extensibility for discount calculations.

macrozheng
macrozheng
macrozheng
Eliminate Complex if‑else with Strategy & Factory Patterns in Spring

The problem of messy if‑else

Business logic inevitably becomes complex as requirements grow, leading to many nested if‑else statements that severely hurt code readability and maintainability.

Using the Strategy pattern together with the Factory pattern and Spring's InitializingBean can eliminate most of those conditionals.

Example requirement

For a food‑delivery platform, different membership levels have distinct discount rules:

Exclusive members get an 8% discount, ordinary members 9%, and non‑members no discount.

Exclusive members receive the discount only when the order amount exceeds 30 yuan.

If a super member's subscription has expired within a week, a one‑time reminder and discount are applied.

public BigDecimal calPrice(BigDecimal orderPrice, String buyerType) {
    if (用户是专属会员) {
        if (订单金额大于30元) {
            return 7折价格;
        }
    }
    if (用户是超级会员) {
        return 8折价格;
    }
    if (用户是普通会员) {
        if (该用户超级会员刚过期并且尚未使用过临时折扣) {
            临时折扣使用次数更新();
            return 8折价格;
        }
        return 9折价格;
    }
    return 原价;
}

This pseudo‑code shows how tangled the logic can become.

Applying the Strategy pattern

Define a common interface:

public interface UserPayService {
    BigDecimal quote(BigDecimal orderPrice);
}

Implement concrete strategies for each membership type:

public class ParticularlyVipPayService implements UserPayService {
    @Override
    public BigDecimal quote(BigDecimal orderPrice) {
        if (orderPrice.compareTo(new BigDecimal("30")) > 0) {
            return new BigDecimal("0.7"); // 7折
        }
        return new BigDecimal("1");
    }
}

public class SuperVipPayService implements UserPayService {
    @Override
    public BigDecimal quote(BigDecimal orderPrice) {
        return new BigDecimal("0.8"); // 8折
    }
}

public class VipPayService implements UserPayService {
    @Override
    public BigDecimal quote(BigDecimal orderPrice) {
        if (用户超级会员刚过期且未使用临时折扣) {
            临时折扣使用次数更新();
            return new BigDecimal("0.8");
        }
        return new BigDecimal("0.9"); // 9折
    }
}

Client code can now select a strategy instance and calculate the price:

public class Test {
    public static void main(String[] args) {
        UserPayService strategy = new VipPayService();
        BigDecimal quote = strategy.quote(new BigDecimal("300"));
        System.out.println("普通会员商品的最终价格为:" + quote.doubleValue());

        strategy = new SuperVipPayService();
        quote = strategy.quote(new BigDecimal("300"));
        System.out.println("超级会员商品的最终价格为:" + quote.doubleValue());
    }
}

Integrating with Spring and the Factory pattern

In a Spring web project, beans are managed by the container, so we retrieve strategy instances from Spring instead of using new:

public BigDecimal calPrice(BigDecimal orderPrice, User user) {
    String vipType = user.getVipType();
    if (vipType.equals("专属会员")) {
        UserPayService strategy = Spring.getBean(ParticularlyVipPayService.class);
        return strategy.quote(orderPrice);
    }
    if (vipType.equals("超级会员")) {
        UserPayService strategy = Spring.getBean(SuperVipPayService.class);
        return strategy.quote(orderPrice);
    }
    if (vipType.equals("普通会员")) {
        UserPayService strategy = Spring.getBean(VipPayService.class);
        return strategy.quote(orderPrice);
    }
    return orderPrice; // 原价
}

To remove the remaining if‑else that selects the bean, a simple factory is introduced:

public class UserPayServiceStrategyFactory {
    private static Map<String, UserPayService> services = new ConcurrentHashMap<>();
    public static UserPayService getByUserType(String type) {
        return services.get(type);
    }
    public static void register(String userType, UserPayService service) {
        services.put(userType, service);
    }
}

Each strategy bean registers itself during initialization:

@Service
public class ParticularlyVipPayService implements UserPayService, InitializingBean {
    @Override
    public BigDecimal quote(BigDecimal orderPrice) { /* ... */ }
    @Override
    public void afterPropertiesSet() {
        UserPayServiceStrategyFactory.register("ParticularlyVip", this);
    }
}

Now the price calculation becomes:

public BigDecimal calPrice(BigDecimal orderPrice, User user) {
    String vipType = user.getVipType();
    UserPayService strategy = UserPayServiceStrategyFactory.getByUserType(vipType);
    return strategy.quote(orderPrice);
}

Conclusion

By combining the Strategy pattern, a simple Factory, and Spring's bean lifecycle, the code eliminates large blocks of if‑else, greatly improving readability and maintainability. The approach is practical for everyday development, and the underlying idea—using design‑pattern thinking rather than strict implementations—remains valuable.

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.

JavaStrategy PatternspringFactory Patternif-else
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

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.