前言:关于传递参数,当参数过多的时候我们可以考虑使用建造者模式。

#没用 Builder模式 之前是这样传参的:

如下所示,构造方法里面的参数一大堆,看起来就非常的混乱。

  • 用了Builder模式之后是这样的

  新建一个静态内部类Buider,通过它来构建参数,然后返回一个新的对象,最后在新的对象内部把值赋给当前类的成员变量,如下图:

  • 可以看到改造后的代码,只存在一个Buider静态内部类,瞬间感觉清晰了不少。

  • 附加一个简单的demo:

    1. class User {
    2. // 下面是“一堆”的属性
    3. private String name;
    4. private String password;
    5. private String nickName;
    6. private int age;
    7.  
    8. // 构造方法私有化,不然客户端就会直接调用构造方法了
    9. private User(String name, String password, String nickName, int age) {
    10. this.name = name;
    11. this.password = password;
    12. this.nickName = nickName;
    13. this.age = age;
    14. }
    15. // 静态方法,用于生成一个 Builder,这个不一定要有,不过写这个方法是一个很好的习惯,
    16. // 有些代码要求别人写 new User.UserBuilder().a()...build() 看上去就没那么好
    17. public static UserBuilder builder() {
    18. return new UserBuilder();
    19. }
    20.  
    21. public static class UserBuilder {
    22. // 下面是和 User 一模一样的一堆属性
    23. private String name;
    24. private String password;
    25. private String nickName;
    26. private int age;
    27.  
    28. private UserBuilder() {
    29. }
    30.  
    31. // 链式调用设置各个属性值,返回 this,即 UserBuilder
    32. public UserBuilder name(String name) {
    33. this.name = name;
    34. return this;
    35. }
    36.  
    37. public UserBuilder password(String password) {
    38. this.password = password;
    39. return this;
    40. }
    41.  
    42. public UserBuilder nickName(String nickName) {
    43. this.nickName = nickName;
    44. return this;
    45. }
    46.  
    47. public UserBuilder age(int age) {
    48. this.age = age;
    49. return this;
    50. }
    51.  
    52. // build() 方法负责将 UserBuilder 中设置好的属性“复制”到 User 中。
    53. // 当然,可以在 “复制” 之前做点检验
    54. public User build() {
    55. if (name == null || password == null) {
    56. throw new RuntimeException("用户名和密码必填");
    57. }
    58. if (age <= 0 || age >= 150) {
    59. throw new RuntimeException("年龄不合法");
    60. }
    61. // 还可以做赋予”默认值“的功能
    62. if (nickName == null) {
    63. nickName = name;
    64. }
    65. return new User(name, password, nickName, age);
    66. }
    67. }
    68. }
    1. 核心是:先把所有的属性都设置给 Builder,然后 build() 方法的时候,将这些属性复制给实际产生的对象。
    2.  
    3. 看看客户端的调用:
    4.  
    5. public class APP {
    6. public static void main(String[] args) {
    7. User d = User.builder()
    8. .name("foo")
    9. .password("pAss12345")
    10. .age(25)
    11. .build();
    12. }
    13. }
  • 2018年1月19日 10:20:12 更新


   附加一个swagger中看到的建造者模式:

  1. /*
  2. *
  3. * Copyright 2015 the original author or authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. *
  18. */
  19.  
  20. package springfox.documentation.builders;
  21.  
  22. import com.fasterxml.classmate.ResolvedType;
  23. import com.google.common.base.Optional;
  24. import springfox.documentation.schema.ModelReference;
  25. import springfox.documentation.service.AllowableValues;
  26. import springfox.documentation.service.Parameter;
  27. import springfox.documentation.service.VendorExtension;
  28.  
  29. import java.util.List;
  30.  
  31. import static com.google.common.collect.Lists.newArrayList;
  32. import static springfox.documentation.builders.BuilderDefaults.*;
  33.  
  34. public class ParameterBuilder {
  35. private String name;
  36. private String description;
  37. private String defaultValue;
  38. private boolean required;
  39. private boolean allowMultiple;
  40. private AllowableValues allowableValues;
  41. private String paramType;
  42. private String paramAccess;
  43. private ResolvedType type;
  44. private ModelReference modelRef;
  45. private boolean hidden;
  46. private List<VendorExtension> vendorExtensions = newArrayList();
  47.  
  48. /**
  49. * Copy builder
  50. *
  51. * @param other parameter to copy from
  52. * @return this
  53. */
  54. ParameterBuilder from(Parameter other) {
  55. return name(other.getName())
  56. .allowableValues(other.getAllowableValues())
  57. .allowMultiple(other.isAllowMultiple())
  58. .defaultValue(other.getDefaultValue())
  59. .description(other.getDescription())
  60. .modelRef(other.getModelRef())
  61. .parameterAccess(other.getParamAccess())
  62. .parameterType(other.getParamType())
  63. .required(other.isRequired())
  64. .type(other.getType().orNull())
  65. .hidden(other.isHidden())
  66. .vendorExtensions(other.getVendorExtentions());
  67. }
  68.  
  69. /**
  70. * Updates the parameter name
  71. *
  72. * @param name - name of the parameter
  73. * @return this
  74. */
  75. public ParameterBuilder name(String name) {
  76. this.name = defaultIfAbsent(name, this.name);
  77. return this;
  78. }
  79.  
  80. /**
  81. * Updates the description of the parameter
  82. *
  83. * @param description - description
  84. * @return this
  85. */
  86. public ParameterBuilder description(String description) {
  87. this.description = defaultIfAbsent(description, this.description);
  88. return this;
  89. }
  90.  
  91. /**
  92. * Updates the default value of the parametr
  93. *
  94. * @param defaultValue - default value
  95. * @return this
  96. */
  97. public ParameterBuilder defaultValue(String defaultValue) {
  98. this.defaultValue = defaultIfAbsent(defaultValue, this.defaultValue);
  99. return this;
  100. }
  101.  
  102. /**
  103. * Updates if the parameter is required or optional
  104. *
  105. * @param required - flag to indicate if the parameter is required
  106. * @return this
  107. */
  108. public ParameterBuilder required(boolean required) {
  109. this.required = required;
  110. return this;
  111. }
  112.  
  113. /**
  114. * Updates if the parameter should allow multiple values
  115. *
  116. * @param allowMultiple - flag to indicate if the parameter supports multi-value
  117. * @return this
  118. */
  119. public ParameterBuilder allowMultiple(boolean allowMultiple) {
  120. this.allowMultiple = allowMultiple;
  121. return this;
  122. }
  123.  
  124. /**
  125. * Updates if the parameter is bound by a range of values or a range of numerical values
  126. *
  127. * @param allowableValues - allowable values (instance of @see springfox.documentation.service.AllowableListValues
  128. * or @see springfox.documentation.service.AllowableRangeValues)
  129. * @return
  130. */
  131. public ParameterBuilder allowableValues(AllowableValues allowableValues) {
  132. this.allowableValues = emptyToNull(allowableValues, this.allowableValues);
  133. return this;
  134. }
  135.  
  136. /**
  137. * Updates the type of parameter
  138. *
  139. * @param paramType - Could be header, cookie, body, query etc.
  140. * @return this
  141. */
  142. public ParameterBuilder parameterType(String paramType) {
  143. this.paramType = defaultIfAbsent(paramType, this.paramType);
  144. return this;
  145. }
  146.  
  147. /**
  148. * Updates the parameter access
  149. *
  150. * @param paramAccess - parameter access
  151. * @return this
  152. */
  153. public ParameterBuilder parameterAccess(String paramAccess) {
  154. this.paramAccess = defaultIfAbsent(paramAccess, this.paramAccess);
  155. return this;
  156. }
  157.  
  158. /**
  159. * Updates the type of parameter
  160. *
  161. * @param type - represents the resolved type of the parameter
  162. * @return this
  163. */
  164. public ParameterBuilder type(ResolvedType type) {
  165. this.type = defaultIfAbsent(type, this.type);
  166. return this;
  167. }
  168.  
  169. /**
  170. * Represents the convenience method to infer the model reference
  171. * Consolidate or figure out whats can be rolled into the other.
  172. *
  173. * @param modelRef
  174. * @return
  175. */
  176. public ParameterBuilder modelRef(ModelReference modelRef) {
  177. this.modelRef = defaultIfAbsent(modelRef, this.modelRef);
  178. return this;
  179. }
  180.  
  181. /**
  182. * Updates if the parameter is hidden
  183. *
  184. * @param hidden - flag to indicate if the parameter is hidden
  185. * @return this
  186. */
  187. public ParameterBuilder hidden(boolean hidden) {
  188. this.hidden = hidden;
  189. return this;
  190. }
  191.  
  192. /**
  193. * Updates the parameter extensions
  194. *
  195. * @param extensions - parameter extensions
  196. * @return this
  197. */
  198. public ParameterBuilder vendorExtensions(List<VendorExtension> extensions) {
  199. this.vendorExtensions.addAll(nullToEmptyList(extensions));
  200. return this;
  201. }
  202.  
  203. public Parameter build() {
  204. return new Parameter(
  205. name,
  206. description,
  207. defaultValue,
  208. required,
  209. allowMultiple,
  210. modelRef,
  211. Optional.fromNullable(type),
  212. allowableValues,
  213. paramType,
  214. paramAccess,
  215. hidden,
  216. vendorExtensions);
  217. }
  218. }

总结:

相比只通过一个构造器创建实例,JavaBean模式的实例的构造过程被分成了好几个过程。

我们完全有可能在属性不完整的情况下使用这个实例。

当然,Builder也有缺点。

缺点1.创建实例前都要创建一个Builder实例。

缺点2.Builder模式编写起来较为冗长。

但是,当构建一个实例需要很多步骤(或者很多让人混淆的参数)的时候,Builder模式是个不错的选择。

    

【原】使用Builder模式替代构造参数传参的更多相关文章

  1. python笔记之强制函数以关键字参数传参

    最近学习python,学到了函数传参,看到了以下这个特殊情况,特此来做个笔记 def add(*, x, y): print(x, y) 以上函数定义后,该怎么传参?前面的那个*号是做什么用的? 我们 ...

  2. Vue系列之 => 使用钩子函数的第二个参数传参

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. Hibernate的HQL语句中定位参数和具名参数传参

    HQL查询: 1.有关hql查询语句中的问号参数形式,如果出现有多个问号,这对后面设置参数就比较麻烦. 如:from User user where user.name=? and user.age= ...

  4. 02.当构造参数过多时使用builder模式

    前言 <Effective Java>中文第三版,是一本关于Java基础的书,这本书不止一次有人推荐我看.其中包括我很喜欢的博客园博主五月的仓颉,他曾在自己的博文<给Java程序猿们 ...

  5. 解析《Effective Java》之多个构造器、Javabeans模式和Builder模式

    最近看<Effective Java>这本被很多同行称为神作的书,但是这本书很多地方缺少了举例不好懂,下面是关于我对书上知识的理解. 一.<Effective Java>中文版 ...

  6. Builder模式在Java中的应用

    在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成.那么,在实际的开发过程中,我们哪些地方适合用到Builder模式呢?其中使用Build ...

  7. Builder模式(建造者模式)

    在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成.那么,在实际的开发过程中,我们哪些地方适合用到Builder模式呢?其中使用Build ...

  8. Builder模式在Java中的应用(转)

    在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成.那么,在实际的开发过程中,我们哪些地方适合用到Builder模式呢?其中使用Build ...

  9. Builder模式详解及其在Android开发中的应用

    一.引言 在Android开发中,采用Builder模式的代码随处可见,比如说Android系统对话框AlertDialog的使用或者是Android中的通知栏(Notification)的使用,又比 ...

随机推荐

  1. 网易云首席安全架构师谈安全新形势:DDOS两三天,游戏玩家数从几万降到几百

    本文由  网易云发布. 安全是一个永恒的话题,在业务不断云化.攻击越来越复杂的当下,互联网安全呈现了出什么样的严峻形势?对这些形势,网易云又是如何应对的? 网易云首席安全架构师沈明星 4月13日,网易 ...

  2. TensorFlow从1到2(十)带注意力机制的神经网络机器翻译

    基本概念 机器翻译和语音识别是最早开展的两项人工智能研究.今天也取得了最显著的商业成果. 早先的机器翻译实际脱胎于电子词典,能力更擅长于词或者短语的翻译.那时候的翻译通常会将一句话打断为一系列的片段, ...

  3. 修改tomcat7编码问题(重定向等)

    修改tomcat默认编码格式: 修改tomcat下的conf/server.xml文件,找到如下代码: <Connector port="8080" protocol=&qu ...

  4. docker registry 私有仓库 安装配置、查询、删除

    #++++++++++++++++++++++++++++++ #docker-registry 私有仓库 #搜索,下载register镜像 docker search registry docker ...

  5. Qt5学习笔记(基础)

    按钮 #include <QApplication> /*应用程序抽象类*/ #include <QWidget> //窗口类 #include <QPushButton ...

  6. LINUX中如何查看某个端口是否被占用

    之前查询端口是否被占用一直搞不明白,问了好多人,终于搞懂了,现在总结下: 1.netstat  -anp  |grep   端口号 如下,我以3306为例,netstat  -anp  |grep   ...

  7. 《JAVA与模式》之桥梁模式

    在阎宏博士的<JAVA与模式>一书中开头是这样描述桥梁(Bridge)模式的: 桥梁模式是对象的结构模式.又称为柄体(Handle and Body)模式或接口(Interface)模式. ...

  8. js的let语句在安卓手机端的QQ浏览器出错的问题

    关于JavaScript里面的let,let 语句可以声明一个块级作用域的本地变量,并且可选的将其初始化为一个值. <ul id="list"> </ul> ...

  9. (转)mysql原生在线ddl和pt-osc原理解析

    原文:http://blog.csdn.net/zengxuewen2045/article/details/52017247 https://github.com/mysql-inception/i ...

  10. Mime、base64编码

    第一部分 在阮一峰老师的博客中,是这样介绍Mime的: MIME的全称是"Multipurpose Internet Mail Extensions",中译为"多用途互联 ...