利用策略模式避免过多if

背景

对于业务开发来说,业务逻辑的复杂是必然的,随着业务发展,需求只会越来越复杂,为了考虑到各种各样的情况,代码中不可避免的会出现很多if-else。一旦代码中if-else过多,就会大大的影响其可读性和可维护性。

假设需求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public BigDecimal calPrice(BigDecimal orderPrice, String buyerType) {

if (用户是专属会员) {
if (订单金额大于30元) {
returen 7折价格;
}
}

if (用户是超级会员) {
return 8折价格;
}

if (用户是普通会员) {
if(该用户超级会员刚过期并且尚未使用过临时折扣){
临时折扣使用次数更新();
returen 8折价格;
}
return 9折价格;
}
return 原价;
}

替换if的方法

定义用户支付接口

1
2
3
4
5
6
7
public interface UserPayService {

/**
* 计算应付价格
*/
public BigDecimal quote(BigDecimal orderPrice);
}

为了方便从Spring中获取UserPayService的各个策略类(也就是实现的接口),创建一个工厂类:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class UserPayServiceStrategyFactory {

private static Map<String,UserPayService> services = new ConcurrentHashMap<String,UserPayService>();

public static UserPayService getByUserType(String type){
return services.get(type);
}

public static void register(String userType,UserPayService userPayService){
Assert.notNull(userType,"userType can't be null");
services.put(userType,userPayService);
}
}

借用Spring种提供的InitializingBean接口将各个实现策略类注册进入工厂类中,这个接口为Bean提供了属性初始化后的处理方法,它只包括afterPropertiesSet方法,凡是继承该接口的类,在bean的属性初始化后都会执行该方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@Service
public class ParticularlyVipPayService implements UserPayService,InitializingBean {

@Override
public BigDecimal quote(BigDecimal orderPrice) {
if (消费金额大于30元) {
return 7折价格;
}
}

@Override
public void afterPropertiesSet() throws Exception {
UserPayServiceStrategyFactory.register("ParticularlyVip",this);
}
}

@Service
public class SuperVipPayService implements UserPayService ,InitializingBean{

@Override
public BigDecimal quote(BigDecimal orderPrice) {
return 8折价格;
}

@Override
public void afterPropertiesSet() throws Exception {
UserPayServiceStrategyFactory.register("SuperVip",this);
}
}

@Service
public class VipPayService implements UserPayService,InitializingBean {

@Override
public BigDecimal quote(BigDecimal orderPrice) {
if(该用户超级会员刚过期并且尚未使用过临时折扣){
临时折扣使用次数更新();
returen 8折价格;
}
return 9折价格;
}

@Override
public void afterPropertiesSet() throws Exception {
UserPayServiceStrategyFactory.register("Vip",this);
}
}

优化后计算价格的代码

1
2
3
4
5
6
public BigDecimal calPrice(BigDecimal orderPrice,User user) {

String vipType = user.getVipType();
UserPayService strategy = UserPayServiceStrategyFactory.getByUserType(vipType);
return strategy.quote(orderPrice);
}

AOP+自定义注解+策略模式 记录操作日志,避免过多的if

https://github.com/haoxiaoyong1014/springboot-examples/tree/master/strategy-aop

参考

https://juejin.im/post/5dad23685188251d2c4ea2b6#comment