策略模式
问题说明
当前项目中,订单的状态比较多,不同状态下取消订单的逻辑是不同的;而且用户不同,可操作的内容也不同
- 普通用户:可取消待支付、派单中、待服务的订单
- 运营人员:可取消派单中、待服务、服务中、完成的订单

因此最终实现取消订单的代码逻辑如下所示:
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接口
package com.jzo2o.orders.manager.service.strategy;
/**
* 支付策略接口
*/
public interface PayStrategy {
//策略方法
void pay();
}
2)定义微信支付策略类
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)定义阿里支付策略类
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)定义上下文环境类
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 //此注解标注的方法会在当前对象PayStrategyManager创建之后自动执行
public void init() {
//key: 当前对象在容器中的id
//value: 当前对象
payStrategyMap = SpringUtil.getBeansOfType(PayStrategy.class);
}
//根据用户需求, 执行指定的策略对象
public void pay(String key) {
PayStrategy payStrategy = payStrategyMap.get(key);
if (payStrategy == null) {
throw new RuntimeException("暂不支持当前支付方式");
}
payStrategy.pay();
}
}
5)测试类
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");
}
}
许可协议:
CC BY 4.0