建造者模式
1.锚定对应的源码
在springMVC中的使用,在springMVC项目的tomcat启动时,项目会创建请求映射集合,就是RequestMapping集合,在这个过程中会调用createRequestMappingInfo(method)方法创建RequestMappingInfo对象,
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对象的赋值
最后调用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));
控制台输出:
拓展知识:
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"}