策略模式

策略模式用于替代大量ifelse的场景, 针对不同的case给出专门的解决方案.

# 示例

需求: 对接一个自动售货机, 服务器向售货机下发命令后, 售货机会返回响应, 服务器收到命令根据命令类型和执行结果做出对应操作

# 1. 定义命令

public enum Action {

    DOOR_OPEN("开门"),

    COMPRESSOR_OPEN("打开压缩机"),
    COMPRESSOR_CLOSE("关闭压缩机"),

    PUSH("出货"),

    QRCODE_ISSUED("下发二维码"),
    MANAGER_PHONE_ISSUED("下发管理员手机号"),

    SHOW_PRODUCT_INFO("展示商品信息"),
    ISSUED_PRODUCT_INFO("下发商品信息"),

    ISSUED_ADVERTISEMENT("下发广告"),
    INVALID_ADVERTISEMENT("失效广告"),

    VOLUME_UP("音量加"),
    VOLUME_DOWN("音量减"),

    MODIFY_PRODUCT_INFO("修改商品信息");


    public String getAction() {
        return action;
    }

    private String action;

    Action(String action) {
        this.action = action;
    }
}

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

# 2. 定义命令响应处理器

@Component
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class CommandResponseHandler {

    // 持有针对各种命令响应成功的不同策略
    private final Map<Action, Consumer<Command>> successConsumerMap = newHashMap();

    // 持有针对各种命令响应失败的不同策略
    private final Map<Action, Consumer<Command>> failureConsumerMap = newHashMap();

    @PostConstruct
    private void initialize() {

        successConsumerMap.put(Action.COMPRESSOR_CLOSE, cmd -> System.out.println("压缩机已关闭"));
        successConsumerMap.put(Action.COMPRESSOR_OPEN, cmd -> System.out.println("压缩机已开启"));
        successConsumerMap.put(Action.QRCODE_ISSUED, cmd -> System.out.println("二维码已下发"));
        successConsumerMap.put(Action.DOOR_OPEN, cmd -> System.out.println("舱门打开"));
        successConsumerMap.put(Action.PUSH, cmd -> System.out.println("出货成功"));
        successConsumerMap.put(Action.ISSUED_ADVERTISEMENT, cmd -> System.out.println("广告下发成功"));
        successConsumerMap.put(Action.INVALID_ADVERTISEMENT, cmd -> System.out.println("广告失效成功"));
        successConsumerMap.put(Action.VOLUME_UP, cmd -> System.out.println("音量加一格"));
        successConsumerMap.put(Action.VOLUME_DOWN, cmd -> System.out.println("音量减一格"));

        failureConsumerMap.put(Action.PUSH, cmd -> System.out.println("出货失败"));
    }

    private void handleSuccessResponse(Command command) {

        // 若没有对应策略, 执行默认策略 c -> {}
        successConsumerMap.getOrDefault(command.getAction(), c -> {}).accept(command);
    }

    private void handleFailureResponse(Command command) {

        // 若没有对应策略, 执行默认策略 c -> {}
        failureConsumerMap.getOrDefault(command.getAction(), c -> {}).accept(command);
    }

    /**
    * 处理命令响应结果
    */
    public void onResponse(CommandResponseResult commandResponseResult) {

        Command command = getCmd(commandResponseResult);

        // 命令成功, 执行成功策略
        if (SUCCESS.equals(command.getResult())) {
            handleSuccessResponse(command);
        } else {
        // 执行失败策略
            handleFailureResponse(command);
        }
    }
    
    private Command getCmd(CommandResponseResult commandResponseResult) {
    
        ...
    }
}

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
  1. CommandResponseHandler在初始化后将各种命令的响应结果对应的处理策略保存到map中
  2. 收到命令响应后调用CommandResponseHandler中的onResponse方法处理
  3. onResponse判断命令成功状态执行handleSuccessResponse或handleFailureResponse
  4. 根据命令类型执行对应策略
上次更新: 2022/3/11 15:12:48