建造者模式

建造者模式

1.锚定对应的源码

在springMVC中的使用,在springMVC项目的tomcat启动时,项目会创建请求映射集合,就是RequestMapping集合,在这个过程中会调用createRequestMappingInfo(method)方法创建RequestMappingInfo对象,

image-20220113161027175

2.注意createRequestMappingInfo方法

createRequestMappingInfo方法,可以看到使用链式调用传入需要的参数最后调用build()快速创建对象。

protected RequestMappingInfo createRequestMappingInfo(
      RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {

   RequestMappingInfo.Builder builder = RequestMappingInfo
         .paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
         .methods(requestMapping.method())
         .params(requestMapping.params())
         .headers(requestMapping.headers())
         .consumes(requestMapping.consumes())
         .produces(requestMapping.produces())
         .mappingName(requestMapping.name());
   if (customCondition != null) {
      builder.customCondition(customCondition);
   }
   return builder.options(this.config).build();
}

3.观察RequestMappingInfo

1.再来看看RequestMappingInfo这个类,可以看到定义了8个变量

public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> {

   @Nullable
   private final String name;

   private final PatternsRequestCondition patternsCondition;

   private final RequestMethodsRequestCondition methodsCondition;

   private final ParamsRequestCondition paramsCondition;

   private final HeadersRequestCondition headersCondition;

   private final ConsumesRequestCondition consumesCondition;

   private final ProducesRequestCondition producesCondition;

   private final RequestConditionHolder customConditionHolder;


   public RequestMappingInfo(@Nullable String name, @Nullable PatternsRequestCondition patterns,
         @Nullable RequestMethodsRequestCondition methods, @Nullable ParamsRequestCondition params,
         @Nullable HeadersRequestCondition headers, @Nullable ConsumesRequestCondition consumes,
         @Nullable ProducesRequestCondition produces, @Nullable RequestCondition<?> custom) {

      this.name = (StringUtils.hasText(name) ? name : null);
      this.patternsCondition = (patterns != null ? patterns : new PatternsRequestCondition());
      this.methodsCondition = (methods != null ? methods : new RequestMethodsRequestCondition());
      this.paramsCondition = (params != null ? params : new ParamsRequestCondition());
      this.headersCondition = (headers != null ? headers : new HeadersRequestCondition());
      this.consumesCondition = (consumes != null ? consumes : new ConsumesRequestCondition());
      this.producesCondition = (produces != null ? produces : new ProducesRequestCondition());
      this.customConditionHolder = new RequestConditionHolder(custom);
   }

在这个对象类中定义了builder内部接口,同时DefaultBuilder实现了builder接口,里面都是对DefaultBuilder对象的赋值

image-20220113161349329

最后调用build()方法,返回RequestMappingInfo对象,完成对象的赋值操作。

@Override
public RequestMappingInfo build() {
   ContentNegotiationManager manager = this.options.getContentNegotiationManager();

   PatternsRequestCondition patternsCondition = new PatternsRequestCondition(
         this.paths, this.options.getUrlPathHelper(), this.options.getPathMatcher(),
         this.options.useSuffixPatternMatch(), this.options.useTrailingSlashMatch(),
         this.options.getFileExtensions());

   return new RequestMappingInfo(this.mappingName, patternsCondition,
         new RequestMethodsRequestCondition(this.methods),
         new ParamsRequestCondition(this.params),
         new HeadersRequestCondition(this.headers),
         new ConsumesRequestCondition(this.consumes, this.headers),
         new ProducesRequestCondition(this.produces, this.headers, manager),
         this.customCondition);
}

思考:

为什么要用建造者模式,如果不用会怎么样?

从源码中可以发现,使用建造者模式,在创建对象的时候,只需要传入需要的参数即可,一行代码便可完成对象的创建,简洁方便

什么是链式调用,原理是什么?优点在哪里?

RequestMappingInfo
         .paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
         .methods(requestMapping.method())
         .params(requestMapping.params())
         .headers(requestMapping.headers())
         .consumes(requestMapping.consumes())
         .produces(requestMapping.produces())
         .mappingName(requestMapping.name());

不断的.参数.参数.参数就是链式调用。其本质原理是在第一次.path的时候new Defaultbuilder返回这个静态内部类对象,后续调用这个静态内部类的方法,且每次返回这个第一次new出来的对象,所以可以不断的调用,再最后调用build()方法,这个方法里就是将Defaultbuilder接受到的参数再调用RequestMappingInfo对象全参的构造方法最后对象。

这里模仿这种方式自己创建了一个user类模拟这个建造者方式

实战:

创建建造者模式的User

package DesignPattern.builder;

import lombok.Data;

@Data
public class User {
    private String name;
    private String code;

    public User(String name, String code) {
        this.name = name;
        this.code = code;
    }

    public interface Builder {
        Builder name(String name);

        Builder code(String name);

        User build();
    }

    public static Builder start() {
        return new DefaultBuilder();
    }

    private static class DefaultBuilder implements Builder {
        private String name;
        private String code;

        @Override
        public DefaultBuilder name(String name) {
            this.name = name;
            return this;
        }

        @Override
        public DefaultBuilder code(String code) {
            this.code = code;
            return this;
        }

        @Override
        public User build() {
            return new User(this.name, this.code);
        }
    }

}

测试调用:

User.Builder user1 = User.start().code("test1").name("测试1");
User user2 = user1.build();
User user3 = User.start().code("test3").name("测试3").build();
User user4 = User.start().code("test4").build();
User user5 = User.start().name("测试5").build();
System.out.println(JSON.toJSONString(user1));
System.out.println(JSON.toJSONString(user2));
System.out.println(JSON.toJSONString(user3));
System.out.println(JSON.toJSONString(user4));
System.out.println(JSON.toJSONString(user5));

控制台输出:

image-20220113181051389

拓展知识:

lombok的@builder注解可以起到同样的作用,再定义完类后,在类标签加上这个注解即可

举个栗子:

@Builder
@Data
public class Student {
    private String name;
    private String code;

    public static void main(String[] args) {
        Student student = Student.builder().code("11").name("lys").build();
        System.out.println(JSON.toJSONString(student));
    }
}

控制台出:

{"code":"11","name":"lys"}
原文地址:https://www.cnblogs.com/yslu/p/15798818.html