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

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

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

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

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

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

  • 附加一个简单的demo:

  • class User {
    // 下面是“一堆”的属性
    private String name;
    private String password;
    private String nickName;
    private int age; // 构造方法私有化,不然客户端就会直接调用构造方法了
    private User(String name, String password, String nickName, int age) {
    this.name = name;
    this.password = password;
    this.nickName = nickName;
    this.age = age;
    }
    // 静态方法,用于生成一个 Builder,这个不一定要有,不过写这个方法是一个很好的习惯,
    // 有些代码要求别人写 new User.UserBuilder().a()...build() 看上去就没那么好
    public static UserBuilder builder() {
    return new UserBuilder();
    } public static class UserBuilder {
    // 下面是和 User 一模一样的一堆属性
    private String name;
    private String password;
    private String nickName;
    private int age; private UserBuilder() {
    } // 链式调用设置各个属性值,返回 this,即 UserBuilder
    public UserBuilder name(String name) {
    this.name = name;
    return this;
    } public UserBuilder password(String password) {
    this.password = password;
    return this;
    } public UserBuilder nickName(String nickName) {
    this.nickName = nickName;
    return this;
    } public UserBuilder age(int age) {
    this.age = age;
    return this;
    } // build() 方法负责将 UserBuilder 中设置好的属性“复制”到 User 中。
    // 当然,可以在 “复制” 之前做点检验
    public User build() {
    if (name == null || password == null) {
    throw new RuntimeException("用户名和密码必填");
    }
    if (age <= 0 || age >= 150) {
    throw new RuntimeException("年龄不合法");
    }
    // 还可以做赋予”默认值“的功能
    if (nickName == null) {
    nickName = name;
    }
    return new User(name, password, nickName, age);
    }
    }
    }
  • 核心是:先把所有的属性都设置给 Builder,然后 build() 方法的时候,将这些属性复制给实际产生的对象。
    
    看看客户端的调用:
    
    public class APP {
    public static void main(String[] args) {
    User d = User.builder()
    .name("foo")
    .password("pAss12345")
    .age(25)
    .build();
    }
    }
  • 2018年1月19日 10:20:12 更新


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

/*
*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/ package springfox.documentation.builders; import com.fasterxml.classmate.ResolvedType;
import com.google.common.base.Optional;
import springfox.documentation.schema.ModelReference;
import springfox.documentation.service.AllowableValues;
import springfox.documentation.service.Parameter;
import springfox.documentation.service.VendorExtension; import java.util.List; import static com.google.common.collect.Lists.newArrayList;
import static springfox.documentation.builders.BuilderDefaults.*; public class ParameterBuilder {
private String name;
private String description;
private String defaultValue;
private boolean required;
private boolean allowMultiple;
private AllowableValues allowableValues;
private String paramType;
private String paramAccess;
private ResolvedType type;
private ModelReference modelRef;
private boolean hidden;
private List<VendorExtension> vendorExtensions = newArrayList(); /**
* Copy builder
*
* @param other parameter to copy from
* @return this
*/
ParameterBuilder from(Parameter other) {
return name(other.getName())
.allowableValues(other.getAllowableValues())
.allowMultiple(other.isAllowMultiple())
.defaultValue(other.getDefaultValue())
.description(other.getDescription())
.modelRef(other.getModelRef())
.parameterAccess(other.getParamAccess())
.parameterType(other.getParamType())
.required(other.isRequired())
.type(other.getType().orNull())
.hidden(other.isHidden())
.vendorExtensions(other.getVendorExtentions());
} /**
* Updates the parameter name
*
* @param name - name of the parameter
* @return this
*/
public ParameterBuilder name(String name) {
this.name = defaultIfAbsent(name, this.name);
return this;
} /**
* Updates the description of the parameter
*
* @param description - description
* @return this
*/
public ParameterBuilder description(String description) {
this.description = defaultIfAbsent(description, this.description);
return this;
} /**
* Updates the default value of the parametr
*
* @param defaultValue - default value
* @return this
*/
public ParameterBuilder defaultValue(String defaultValue) {
this.defaultValue = defaultIfAbsent(defaultValue, this.defaultValue);
return this;
} /**
* Updates if the parameter is required or optional
*
* @param required - flag to indicate if the parameter is required
* @return this
*/
public ParameterBuilder required(boolean required) {
this.required = required;
return this;
} /**
* Updates if the parameter should allow multiple values
*
* @param allowMultiple - flag to indicate if the parameter supports multi-value
* @return this
*/
public ParameterBuilder allowMultiple(boolean allowMultiple) {
this.allowMultiple = allowMultiple;
return this;
} /**
* Updates if the parameter is bound by a range of values or a range of numerical values
*
* @param allowableValues - allowable values (instance of @see springfox.documentation.service.AllowableListValues
* or @see springfox.documentation.service.AllowableRangeValues)
* @return
*/
public ParameterBuilder allowableValues(AllowableValues allowableValues) {
this.allowableValues = emptyToNull(allowableValues, this.allowableValues);
return this;
} /**
* Updates the type of parameter
*
* @param paramType - Could be header, cookie, body, query etc.
* @return this
*/
public ParameterBuilder parameterType(String paramType) {
this.paramType = defaultIfAbsent(paramType, this.paramType);
return this;
} /**
* Updates the parameter access
*
* @param paramAccess - parameter access
* @return this
*/
public ParameterBuilder parameterAccess(String paramAccess) {
this.paramAccess = defaultIfAbsent(paramAccess, this.paramAccess);
return this;
} /**
* Updates the type of parameter
*
* @param type - represents the resolved type of the parameter
* @return this
*/
public ParameterBuilder type(ResolvedType type) {
this.type = defaultIfAbsent(type, this.type);
return this;
} /**
* Represents the convenience method to infer the model reference
* Consolidate or figure out whats can be rolled into the other.
*
* @param modelRef
* @return
*/
public ParameterBuilder modelRef(ModelReference modelRef) {
this.modelRef = defaultIfAbsent(modelRef, this.modelRef);
return this;
} /**
* Updates if the parameter is hidden
*
* @param hidden - flag to indicate if the parameter is hidden
* @return this
*/
public ParameterBuilder hidden(boolean hidden) {
this.hidden = hidden;
return this;
} /**
* Updates the parameter extensions
*
* @param extensions - parameter extensions
* @return this
*/
public ParameterBuilder vendorExtensions(List<VendorExtension> extensions) {
this.vendorExtensions.addAll(nullToEmptyList(extensions));
return this;
} public Parameter build() {
return new Parameter(
name,
description,
defaultValue,
required,
allowMultiple,
modelRef,
Optional.fromNullable(type),
allowableValues,
paramType,
paramAccess,
hidden,
vendorExtensions);
}
}

总结:

相比只通过一个构造器创建实例,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. 如何将Spring Boot项目打包部署到外部Tomcat

    1.项目打包     项目开发结束后,需要打包部署到外部服务器的Tomcat上,主要有几种方式. (1)生成jar包 cd 项目跟目录(和pom.xml同级)mvn clean package## 或 ...

  2. ZZNU 2055(基姆拉尔森计算公式)

    题目链接 题意: 比如今天是2017年8月16日,星期三.下一个也是星期三的8月16日发生在2023年. 现在是日期是yyyy-mm-dd,我们希望你求出薛定谔会跳跃到那一年. 题解: emmmm.. ...

  3. 利用nginx实现负载均衡

    1.安装nginx和tomcat 我这里是使用docker安装的.安装流程可参照 dockerfile 这里安装了两个tomcat,端口分别是42000和42001.第二个tomcat的首页随便加了些 ...

  4. JavaScript函数学习总结(一)---函数定义

    博客原文地址:Claiyre的个人博客 如需转载,请在文章开头注明原文地址 在许多传统的OO语言中,对象可以包含数据,还可拥有方法,也就是属于该对象的函数.但在JavaScript中,函数也被认为是一 ...

  5. Swift 里字符串(七)stringIndex

    在 String 里,用来索引 Character 的,不是整数,而是StringIndex 内部结构 extension String { /// A position of a character ...

  6. docker下 klee第一个测试

    被测试的简单函数源文件位于  /klee_src/examples/get_sign 目录下 该源代码分为三个部分 第一个部分为被测试的函数 int get_sign(int x) { if (x = ...

  7. Mac下使用zsh不执行/etc/profile文件

    Mac下使用了zsh会不执行/etc/profile文件,当然,如果用原始的是会执行. 转而执行的是这两个文件,每次登陆都会执行: ~/.zshrc与/etc/zshenv与/etc/zshrc 所以 ...

  8. DotNetOpenAuth 服务端搭建

    新建项目: 安装DotNetOpenAuth: 新增OAuthController: 代码如下: public class OAuthController : Controller { private ...

  9. C/C++练习题(二)

    1.下面这些指针分别代表什么? float(**p1)[10]; double*(*p2)[10]; double(*p3[10])(); int*((*p4)[10]); long(**p5)(in ...

  10. linux内核移植过程问题总结

    移植内核:2.6.30.4内核根目录下的.config为当前配置内核的且已经配置好的内核配置.make zImage以此为依据配置内核的过程:cd linux-2.6.30.4(进入Linux根目录) ...