策略模式概念

https://refactoringguru.cn/design-patterns/strategy

实战应用

背景

健康码组件对接的前端门禁设备都多种开门的方式,刷证,人脸,二维码等。对于每一种开门方式,其需要的返回结果是一样的,只是内部的处理方式不一样。所以这里使用策略模式+工厂模式来实现,通过一个入口以及不同的type来实现调用不同的实现类。具体代码如下。

代码

1. 创建一个Handler接口类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
/**
 * @Author Yuanpeng
 * @Description 处理健康码请求携带参数的类 根据不同的类型进行 不同的处理
 * @Date 2022/1/10
 */
public interface HealthCodeHandler {

    /**
     * 处理健康码信息的逻辑
     * @param query 前置信息
     * @return 处理的结果 包括开门信息 健康码信息 核酸信息 疫苗信息等
     */
    HealthCodeResult handle(HealthCodeQuery query);

    /**
     * 获取请求的类型 1.人员唯一标识 personId 2.身份证号 3.二维码 4.人员卡号 5.人脸图片 6.市民卡
     * @return 类型
     */
    Integer getType();
}

2. 创建不同的Handler实现类,这里以二维码的实现类举例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
/**
 * @Author Yuanpeng
 * @Description 处理二维码的实现类
 * @Date 2022/1/10
 */
@Service
public class QrCodeHandler implements HealthCodeHandler {

    private static final Logger log = LoggerFactory.getLogger(QrCodeHandler.class);

    @Override
    public HealthCodeResult handle(HealthCodeQuery query) {
        HealthCodeResult result = ResultUtils.getDefaultHeathCodeResult(query, false);
        // logic code
        return result;
    }

    @Override
    public Integer getType() {
        return HealthCodeConstants.QR_CODE_TYPE;
    }

3. 将所有实现了Handler接口类的实例注入容器

 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
/**
 * @Author Yuanpeng
 * @Description 策略模式的工厂类 加载所有的HealthCodeHandler类
 * @Date 2022/1/10
 */
@Component
public class HealthCodeHandlerFactory implements InitializingBean, ApplicationContextAware {

    private static final Map<Integer, HealthCodeHandler> HEALTH_CODE_HANDLER_MAP = new HashMap<>(6);

    private ApplicationContext appContext;

    /**
     * 根据健康码信息类型获取对应的处理器
     *
     * @param type 健康码信息类型
     * @return 健康码信息类型对应的处理器
     */
    public HealthCodeHandler getHandler(Integer type) {
        return HEALTH_CODE_HANDLER_MAP.get(type);
    }

    @Override
    public void afterPropertiesSet() {
        // 将 Spring 容器中所有的 HealthCodeHandler 注册到 FORM_SUBMIT_HANDLER_MAP
        appContext.getBeansOfType(HealthCodeHandler.class)
                .values()
                .forEach(handler -> HEALTH_CODE_HANDLER_MAP.put(handler.getType(), handler));
    }

    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
        appContext = applicationContext;
    }
}

4. 入口处根据传参中的type进行不同类的调用

1
2
3
    // 使用策略模式来实现对不同类型请求的处理,如果需要添加其它类型信息的处理 只需要实现相应的HealthCodeHandler即可
    HealthCodeHandler handler = healthCodeHandlerFactory.getHandler(query.getCardNoType());
    HealthCodeResult result = handler.handle(query);

至此,完成了业务上的需求,同时后期如果还有其它类型的开门方式,可以直接写实现类,不用改之前的代码,维护起来比较方便。