策略设计模式在spring源码中的应用
策略设计模式的使用
我就结合着我自己的学习,来讲下,我对策略模式的一些理解,首先说,使用背景,简单来说,就是有多种策略的场景下使用,这个说的好像是个废话,举个简单的例子吧
我们就模拟下springmvc源码中,对请求参数的解析逻辑
参数解析接口
public interface ParamResolve {
/**
* 判断当前解析类是否可以解析param该参数,返回true表示支持,返回false表示不支持
* @param param
* @return
*/
boolean isSupportResolve(Object param);
/**
* 解析参数
* @param param
*/
void resolveParam(Object param);
}
参数解析实现类
public class JsonResolve implements ParamResolve{
@Override
public boolean isSupportResolve(Object param) {
return "Json".equals(param);
}
@Override
public void resolveParam(Object param) {
System.out.println("解析json参数");
}
}
public class ListResolve implements ParamResolve {
@Override
public boolean isSupportResolve(Object param) {
return "List".equals(param);
}
@Override
public void resolveParam(Object param) {
System.out.println("解析list参数");
}
}
public class StringResolve implements ParamResolve{
@Override
public boolean isSupportResolve(Object param) {
return "String".equals(param);
}
@Override
public void resolveParam(Object param) {
System.out.println("对String类型的参数进行解析");
}
}
这里我模拟了三个参数解析器,分别是对String参数的解析,json参数的解析、list类型参数的解析,只是简单的模拟下demo
我们需要考虑,虽然我提供了三个参数解析器,但是我怎么知道哪个参数是要被哪个解析器去解析呢?那这时候就需要一个额外的类,去管理所有的参数解析器
public class Context {
public static void main(String[] args) {
List<ParamResolve> paramResolves = new ArrayList<>();
paramResolves.add(new ListResolve());
paramResolves.add(new StringResolve());
paramResolves.add(new JsonResolve());
test(paramResolves,"String");
test(paramResolves,"Json");
test(paramResolves,"List");
}
public static void test(List<ParamResolve> paramResolves,String str){
for (ParamResolve paramResolve: paramResolves) {
if(paramResolve.isSupportResolve(str)){
paramResolve.resolveParam(str);
}
}
}
}
这就是参数管理所有参数解析器的类,也就是说,如果这时候入参的是String类型的参数,我会先调用isSupportResolve方法,如果这个方法返回的是true,就表示当前解析器就可以解析这个参数,那接着就会调用它的解析方法去解析这个参数
那如果我这时候,需要去扩展第四个参数解析器怎么办?因为我还可能提供对Map类型参数的解析、对Integer类型参数的解析?那只需要去实现ParamResolve接口,然后将实现类,放到paramResolves这个list集合中即可
我觉得这就是策略设计模式的应用
在spring源码中的应用
那其实springmvc源码中,参数解析器就是策略模式的应用,如果看过springmvc参数解析源码的同学,就会发现,我上面写得demo,和springmvc参数解析的逻辑神似,
参数解析器接口
可以看到,在这个接口中,只定义了两个方法,分别是是否支持该参数的解析,第二个是参数解析的方法
org.springframework.web.method.support.HandlerMethodArgumentResolver
public interface HandlerMethodArgumentResolver {
boolean supportsParameter(MethodParameter var1);
Object resolveArgument(MethodParameter var1, ModelAndViewContainer var2, NativeWebRequest var3, WebDataBinderFactory var4) throws Exception;
}

可以看到,spring自己本身就提供了N多个参数解析器
那这时候问题就来了,这些spring自带的参数解析器是在什么时候添加到spring源码中的list集合中的?这个问题最后说吧
那对于spring的源码中,我们如何将自定义的参数解析器,添加到spring容器中的呢?
在spring源码中,也是用的一个list集合来存放所有的参数解析器,所以,只需要将我们自己定义的参数解析器,放入到这个list集合中即可
org.springframework.web.method.support.HandlerMethodArgumentResolverComposite#argumentResolvers
private final List<HandlerMethodArgumentResolver> argumentResolvers =
new LinkedList<HandlerMethodArgumentResolver>();
那怎么放到这个list中呢?spring也提供了扩展点,只需要实现WebMvcConfigurer这个接口,然后实现它的addArgumentResolvers()方法即可,具体,可以参考前面我的一篇笔记 springmvc应用-自定义参数解析器
那我们放入到了集合之后,在发起调用的时候,spring会遍历这个list集合,然后对请求的中的参数,依次调用
伪代码大致就是这样的:
for(HandlerMethodArgumentResolver 参数解析器:参数解析器list集合){
for(Param param:params){
if(参数解析器.isSupport(param)){
参数解析器.解析参数
}
}
}
spring源码中,当然不会蠢到这样去处理,在其内部它会用一个map集合,存下来参数所对应的解析器,这样在重复调用的时候,就不需要再次解析了,这里只是伪代码的实现
所以,这就是策略设计模式的使用和在spring源码中的应用
我觉得spring的强大之处就在于:自己本身已经足够强大了,如果自己提供的一些功能还是满足不了程序员的业务需求,那怎么办呢?没关系,我spring提供了一系列的扩展点,足够来让程序员去扩展,简直是一条龙服务
spring自带的参数解析器,如何放到list集合中
最简单的一个办法,我们在所有addResolve的地方,debug打上断点,然后看下,是在哪里调用的,其实是在RequestMappingHandlerAdapter这个bean初始化的时候,将所有默认的参数解析器,添加到list集合中的,

可以看到,它实现了初始化回调的接口,所以,在afterPropertiesSet()方法中,提供了addResolve的逻辑
public void afterPropertiesSet() {
this.initControllerAdviceCache();
List handlers;
if (this.argumentResolvers == null) {
handlers = this.getDefaultArgumentResolvers();
this.argumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(handlers);
}
if (this.initBinderArgumentResolvers == null) {
handlers = this.getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(handlers);
}
if (this.returnValueHandlers == null) {
handlers = this.getDefaultReturnValueHandlers();
this.returnValueHandlers = (new HandlerMethodReturnValueHandlerComposite()).addHandlers(handlers);
}
}

所以,这就是默认的参数解析器,是如何放到list的答案
优缺点
策略设计模式的优点:
策略设计模式是对开闭原则的完美诠释,如果我要新增一个策略,只需要添加新的策略即可,不会对原有的算法和策略产生影响
缺点:
使用者需要知道每个策略的具体实现,来决定使用哪个策略
本文介绍了策略设计模式的使用,通过模拟Spring MVC参数解析,展示了如何管理和扩展参数解析器。在Spring源码中,参数解析器的实现应用了策略模式,允许通过实现特定接口并添加到容器列表中进行扩展。文章还探讨了Spring自带参数解析器的添加方式,并讨论了策略模式的优缺点。
1435

被折叠的 条评论
为什么被折叠?



