【Java】SpringBoot优雅的策略模式

发布于:2025-03-27 ⋅ 阅读:(109) ⋅ 点赞:(0)

案例

以消息内容解析器为例。一个消息根据不同的消息类型,选用不同的消息内容解析器。

  1. 先定义一个消息内容实体类
/**
* @Description 消息内容实体类
*/
@Data
public class MessageEntity {
   // 消息类型
   private String messageType;
   // 消息内容
   private String content;
}
  1. 定义一个策略的接口
/**
 3. @Description 消息策略接口
 */
public interface MessageParser {
    /**
     * 是否支持该类型的消息
     * @param messageType 消息内容
     * @return vo
     */
    boolean supports(MessageEntity messageType);

    /**
     * 解析消息
     * @param content 消息内容
     * @return map
     */
    Map<String,Object> parse(MessageEntity content);
}
  1. 编写两个接口的实现类
@Service
public class DefaultMessageParser implements MessageParser {
    @Override
    public boolean supports(MessageEntity message) {
        return "default".equals(message.getMessageType());
    }

    @Override
    public Map<String, Object> parse(MessageEntity content) {
        // 实现具体解析逻辑
        // ........
        HashMap<String, Object> map = new HashMap<>(10);
        map.put("content", content);
        map.put("cityCode","3501");
        return map;
    }
}
@Service
public class JsonMessageParser implements MessageParser {
    @Override
    public boolean supports(MessageEntity message) {
        return "json".equals(message.getMessageType());
    }

    @Override
    public Map<String, Object> parse(MessageEntity content) {
        // 实现具体解析逻辑
        // ........
        HashMap<String, Object> map = new HashMap<>(10);
        map.put("content", content);
        map.put("json","{}");
        return map;
    }
}
  1. 编写消息内容策略分发器
@Service
@RequiredArgsConstructor
public class MessageParserDispatcher {

    private final List<MessageParser> parsers;

    public Map<String,Object> parse(MessageEntity message){
        return parsers.stream().filter(p -> p.supports(message))
                .findFirst().orElseThrow(IllegalArgumentException::new).parse(message);
    }

}
  1. 写一个控制层进行测试
@RestController
@RequiredArgsConstructor
public class ParserController {
	// 这里只需要引入 策略分发器即可
    private final MessageParserDispatcher messageParserDispatcher;

    @GetMapping("test/{messageType}")
    public Map<String, Object> test(@PathVariable String messageType){
        MessageEntity messageEntity = new MessageEntity();
        messageEntity.setContent("hello world");
        messageEntity.setMessageType(messageType);
        return messageParserDispatcher.parse(messageEntity);
    }

}

测试结果
可以看到不同的消息类型选用了不同的策略方式。
在这里插入图片描述
在这里插入图片描述

总结

SpringBoot中使用策略模式还是很简单的。一个接口多个实现,多个实现都使用@Service注册到Spring容器中,然后在策略分发器MessageParserDispatcher中注入成一个实现类的集合列表。同样实现一个一模一样的方法parse() 然后通过stream流找到支持解析的实现类调用该实现类的parse()
后续有新增实现类,实现接口后@Service注册即可

扩展

@Service
@RequiredArgsConstructor
public class MessageParserDispatcher {

    private final List<MessageParser> parsers;

    public Map<String,Object> parse(MessageEntity message){
        return parsers.stream().filter(p -> p.supports(message))
                .findFirst().orElseThrow(IllegalArgumentException::new).parse(message);
    }

}

这里的注入属性parsers 没有采用@Autowired或者@Resource
而是采用了lombok@RequiredArgsConstructor 配合final关键字
实际上用的构造函数注入,@Autowired的用法官方更推荐使用构造函数注入,而lombok会给标记了final的属性在编译时创建构造函数。
所以实际上代码如下,个人觉得这种写法还是比较清爽的。

@Service
public class MessageParserDispatcher {
    private final List<MessageParser> parsers;

    public Map<String, Object> parse(MessageEntity message) {
        return ((MessageParser)this.parsers.stream().filter((p) -> {
            return p.supports(message);
        }).findFirst().orElseThrow(IllegalArgumentException::new)).parse(message);
    }

    public MessageParserDispatcher(final List<MessageParser> parsers) {
        this.parsers = parsers;
    }
}

网站公告

今日签到

点亮在社区的每一天
去签到