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.
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.
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.
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.
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.
