本文学习Spring框架中使用的Builder模式,从模仿到应用(举个例子)。
builder模式理解
导读.
所以,如果你读了上面的例子,会发现几个不变的东西:
- 意图是什么: 就是你认为用户搞不清楚构造过程,只知道要构建哪些东西,只关注结果而不是过程的老板
- 举个例子: 麦当劳的套餐组合,电脑的组装,构造一个文件等等
那么我们就可以开始了。
Spring中的Builder
在IDEA里输入Builder,借助智能提示,我们可以找到很多spring里的Builder类,而且大多数是内部类,以下是一些例子:
1 2 3 4 5 6
| import org.springframework.boot.autoconfigure.condition.ConditionMessage; import org.springframework.cache.interceptor.CachePutOperation; import org.springframework.http.ContentDisposition; import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
具体细节展示:
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 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
| public final class ConditionMessage { private String message;
private ConditionMessage(String message) { this.message = message; }
public static ConditionMessage.Builder forCondition(String condition, Object... details) { return (new ConditionMessage()).andCondition(condition, details); }
public final class Builder { private final String condition;
private Builder(String condition) { this.condition = condition; }
public ConditionMessage foundExactly(Object result) { return this.found("").items(result); } } }
public class ContentDisposition {
private ContentDisposition(@Nullable String type, @Nullable String name, @Nullable String filename, @Nullable Charset charset, @Nullable Long size, @Nullable ZonedDateTime creationDate, @Nullable ZonedDateTime modificationDate, @Nullable ZonedDateTime readDate) { this.type = type; this.name = name; this.filename = filename; this.charset = charset; this.size = size; this.creationDate = creationDate; this.modificationDate = modificationDate; this.readDate = readDate; }
public static ContentDisposition.Builder builder(String type) { return new ContentDisposition.BuilderImpl(type); }
public interface Builder { ContentDisposition.Builder name(String var1);
ContentDisposition.Builder filename(String var1);
ContentDisposition.Builder filename(String var1, Charset var2);
ContentDisposition.Builder size(Long var1);
ContentDisposition.Builder creationDate(ZonedDateTime var1);
ContentDisposition.Builder modificationDate(ZonedDateTime var1);
ContentDisposition.Builder readDate(ZonedDateTime var1);
ContentDisposition build(); } }
public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> {
public static RequestMappingInfo.Builder paths(String... paths) { return new RequestMappingInfo.DefaultBuilder(paths); }
public interface Builder { RequestMappingInfo.Builder paths(String... var1);
RequestMappingInfo.Builder methods(RequestMethod... var1);
RequestMappingInfo.Builder params(String... var1);
RequestMappingInfo.Builder headers(String... var1);
RequestMappingInfo.Builder consumes(String... var1);
RequestMappingInfo.Builder produces(String... var1);
RequestMappingInfo.Builder mappingName(String var1);
RequestMappingInfo.Builder customCondition(RequestCondition<?> var1);
RequestMappingInfo.Builder options(RequestMappingInfo.BuilderConfiguration var1);
RequestMappingInfo build(); } }
|
我想敏感的人已经看出来这是一个统一的模式,模式如下:
- Builder都是被构建类的内部类,且被构建类提供了一个静态创建Builder的方法
- Builder会返回构建的类,可能通过
build()
方法,也可能其他方法
- 构建过程有很多参数,如果参数少,直接用构造函数好一点,且参数可以有默认值,用户只需选择想要的参数
现在我们提取出这套模式代码:
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
| public class BuilderTemplate {
private Object param1; private Object param2;
private BuilderTemplate(Object param1, Object param2) { this.param1 = param1; this.param2 = param2; }
public static Builder builder(Object... params) { return new BuilderImpl(); }
private static class BuilderImpl implements Builder { Object param1; Object param2;
@Override public Builder method1(Object param1) { this.param1 = param1; return this; }
@Override public Builder method2(Object param2) { this.param2 = param2; return this; }
@Override public BuilderTemplate build() { return new BuilderTemplate(param1, param2); } }
public interface Builder { Builder method1(Object param1);
Builder method2(Object param2);
BuilderTemplate build(); } }
|
如何使用呢?我想大家已经很熟悉了:
1 2 3 4 5
| final BuilderTemplate template = BuilderTemplate.builder() .method1("1") .method2("2") .build();
|
模仿到应用
假如我们开了个对象中介所,给广大男女找寻另一半,伟大的工作,哈。
关键来了:找对象的人只会提要求(身高,体重,美貌,家境等),而不知道如何去找这样的人,这个就交给我们了。
为了简化一点,我们暂时只定义以下4条件:
- 身高(cm)
- 年龄(范围)
- 颜值(数字1-10)
- 收入(最低)
当然有些人没有条件,只要是异性就行(鉴于我国法律还没有允许同性婚姻,暂时保持异性把),这样就可以什么条件都不传。
以下就是按照模板写的例子:
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 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
| import org.springframework.util.Assert;
import java.util.ArrayList; import java.util.List;
public class MarriageAgency { private Description desc;
public MarriageAgency(Description desc) { this.desc = desc; }
public static Builder builder() { return new BuilderImpl(); }
public List<String> findMate(Description client) { desc.sex = client.sex == 0 ? 1 : 0; return new ArrayList<>(); }
public static class Description { int height; Age age; int income; int beautiness;
int sex; }
private static class Age { int low; int high;
public Age(int low, int high) { this.low = low; this.high = high; } }
private static class BuilderImpl implements Builder {
Description desc;
@Override public Builder height(int height) { Assert.isTrue(height > 10 && height < 300, "这不是合法的人类高度"); this.desc.height = height; return this; }
@Override public Builder ageBetween(int low, int high) { this.desc.age = new Age(low, high); return this; }
@Override public Builder income(int low) { this.desc.income = low; return this; }
@Override public Builder beautiness(int value) { this.desc.beautiness = value; return this; }
@Override public MarriageAgency build() { return null; } }
public interface Builder { Builder height(int height);
Builder ageBetween(int low, int high);
Builder income(int low);
Builder beautiness(int value);
MarriageAgency build(); } }
|
使用:
1 2 3 4 5 6 7
| final MarriageAgency agency = MarriageAgency.builder() .ageBetween(20, 30) .beautiness(9) .height(160) .income(10000) .build(); agency.findMate(new Description());
|