策略模式
问题说明
当前项目中,订单的状态比较多,不同状态下取消订单的逻辑是不同的;而且用户不同,可操作的内容也不同
- 普通用户:可取消待支付、派单中、待服务的订单
- 运营人员:可取消派单中、待服务、服务中、完成的订单
因此最终实现取消订单的代码逻辑如下所示:
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
| public void cancel(OrderCancelDTO orderCancelDTO) { Orders orders = getById(orderCancelDTO.getId()); Integer ordersStatus = orders.getOrdersStatus(); CurrentUserInfo currentUserInfo = UserContext.currentUser(); Integer userType = currentUserInfo.getUserType(); if(UserType.C_USER==userType){ if(OrderStatusEnum.NO_PAY.getStatus()==ordersStatus){ }else if(OrderStatusEnum.DISPATCHING.getStatus()==ordersStatus){ }else if(OrderStatusEnum.NO_SERVE.getStatus()==ordersStatus){ }else{ throw new CommonException("当前订单状态不支持取消"); } }else if(UserType.OPERATION==userType){ if(OrderStatusEnum.DISPATCHING.getStatus()==ordersStatus) { }else if(OrderStatusEnum.NO_SERVE.getStatus()==ordersStatus){ }else if(OrderStatusEnum.SERVING.getStatus()==ordersStatus){ }else if(OrderStatusEnum.FINISHED.getStatus()==ordersStatus){ }else{ throw new CommonException("当前订单状态不支持取消"); } } }
|
这种代码虽然可以实现功能,但是可读性和扩展性都很差,我们可以使用策略模式进行改造
策略模式
使用场景:针对一个业务,有多个不同的执行分支,需要根据不同的条件,切换到不同的分支上去
好处:解决使用条件语句(如if…else)导致的复杂性和扩展性问题
策略模式需要开发下面的接口和类:
- 策略接口:定义策略方法
- 策略实现类:需要实现策略接口,并重写接口中声明的策略方法
- 上下文环境类:需要维护所有策略对象,然后根据不同的条件,调用不同的策略对象
下面以一个**支付方式**选择的场景为例子来讲解一下,需求如下:
- 当前项目支持微信和阿里两种支付方式
- 用户可以自行选择一种支付方式
- 根据用户选择,执行对应的支付代码
1)定义策略接口
创建PayStrategy接口
1 2 3 4 5 6 7 8 9 10
| package com.jzo2o.orders.manager.service.strategy;
public interface PayStrategy {
void pay(); }
|
2)定义微信支付策略类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package com.jzo2o.orders.manager.service.strategy.impl;
import com.jzo2o.orders.manager.service.strategy.PayStrategy; import org.springframework.stereotype.Component;
@Component("wxPay") public class WxPayStrategy implements PayStrategy { @Override public void pay() { System.out.println("使用微信进行支付"); } }
|
3)定义阿里支付策略类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package com.jzo2o.orders.manager.service.strategy.impl;
import com.jzo2o.orders.manager.service.strategy.PayStrategy; import org.springframework.stereotype.Component;
@Component("aliPay") public class AliPayStrategy implements PayStrategy { @Override public void pay() { System.out.println("使用阿里进行支付"); } }
|
4)定义上下文环境类
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
| package com.jzo2o.orders.manager.service.strategy;
import cn.hutool.extra.spring.SpringUtil; import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct; import java.util.Map;
@Component public class PayStrategyManager { Map<String, PayStrategy> payStrategyMap;
@PostConstruct public void init() { payStrategyMap = SpringUtil.getBeansOfType(PayStrategy.class); }
public void pay(String key) { PayStrategy payStrategy = payStrategyMap.get(key); if (payStrategy == null) { throw new RuntimeException("暂不支持当前支付方式"); } payStrategy.pay(); } }
|
5)测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package com.jzo2o.orders.manager.service.strategy;
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest public class PayTest {
@Autowired private PayStrategyManager payStrategyManager;
@Test public void test(){ payStrategyManager.pay("wxPay"); payStrategyManager.pay("aliPay"); } }
|