【原】使用Builder模式替代构造参数传参
前言:关于传递参数,当参数过多的时候我们可以考虑使用建造者模式。
#没用 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模式替代构造参数传参的更多相关文章
- python笔记之强制函数以关键字参数传参
最近学习python,学到了函数传参,看到了以下这个特殊情况,特此来做个笔记 def add(*, x, y): print(x, y) 以上函数定义后,该怎么传参?前面的那个*号是做什么用的? 我们 ...
- Vue系列之 => 使用钩子函数的第二个参数传参
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Hibernate的HQL语句中定位参数和具名参数传参
HQL查询: 1.有关hql查询语句中的问号参数形式,如果出现有多个问号,这对后面设置参数就比较麻烦. 如:from User user where user.name=? and user.age= ...
- 02.当构造参数过多时使用builder模式
前言 <Effective Java>中文第三版,是一本关于Java基础的书,这本书不止一次有人推荐我看.其中包括我很喜欢的博客园博主五月的仓颉,他曾在自己的博文<给Java程序猿们 ...
- 解析《Effective Java》之多个构造器、Javabeans模式和Builder模式
最近看<Effective Java>这本被很多同行称为神作的书,但是这本书很多地方缺少了举例不好懂,下面是关于我对书上知识的理解. 一.<Effective Java>中文版 ...
- Builder模式在Java中的应用
在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成.那么,在实际的开发过程中,我们哪些地方适合用到Builder模式呢?其中使用Build ...
- Builder模式(建造者模式)
在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成.那么,在实际的开发过程中,我们哪些地方适合用到Builder模式呢?其中使用Build ...
- Builder模式在Java中的应用(转)
在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成.那么,在实际的开发过程中,我们哪些地方适合用到Builder模式呢?其中使用Build ...
- Builder模式详解及其在Android开发中的应用
一.引言 在Android开发中,采用Builder模式的代码随处可见,比如说Android系统对话框AlertDialog的使用或者是Android中的通知栏(Notification)的使用,又比 ...
随机推荐
- PHP7 - 如何禁用Xdebug
操作系统:Cent OS 7 什么是Xdebug?看它的官方网站介绍: https://xdebug.org/index.php 为什么要禁用呢?这是因为Composer,这两种工具有冲突,在使用Co ...
- laravel 的passport Oauth 认证登录请求 的 oauth_token 重置
laravel 的passport Oauth 认证登录请求 的 oauth_token 重置 使用API登录认证是需要获取访问令牌,方法为: 参数: grant_type —— 密码模式固定为 ...
- 算法(Algorithm)
算法就是"把解决问题的步骤无一遗漏地用文字或图表示出来". 在解决问题的步骤中,有了与直觉相关的因素,就不是算法了.既然不是算法,也就不能用程序表示了.
- docker私服registry管理镜像
前言 首先试想这样一个场景:当在自己的机器上(docker中)构建了mysql镜像,eureka镜像等等微服务镜像,这些镜像有可能需要放到其他的机器上docker环境中去运行,实行分布式架构部署.但如 ...
- linux中进程和计划任务管理
进程和计划任务管理 1. 程序和进程的关系 程序:保存在硬盘.光盘等介质中的可执行代码和数据:静态保存的代码 进程:在 CPU 及内存中运行的程序代码:动态执行的代码:父.子进程:每个进程可以创建一个 ...
- 解决后台json数据返回的字段需要替换的问题
有时候后台json数据返回的字段含有“id”,也有可能是有时候为了减少代码的冗余,两页面之间只是数据模型个别属性的区别,所以这时候最好是用到模型属性的替换,用新的属性替换返回的json数据的字段.这里 ...
- POJ 1243
#include <iostream> #include <algorithm> #include <cmath> #define MAXN 50 using na ...
- C++ 实现Biginteger
网上C++版Biginteger参差不齐,一下子没有找到一个令人满意Biginteger,最近用c++改写了一下C#版 BigInteger,可以用于RSA大素数的生成,分享给大家.也请大家批评指正改 ...
- openssl生成RSA格式的公私钥,并转为pkcs8格式
第一步:生成私钥,这里我们指定私钥的长度为2048 openssl genrsa -out rsa_private_key.pem 2048 第二步:根据私钥生成对应的公钥: openssl rsa ...
- [转]MVC HtmlHelper用法大全
原文链接:http://www.cnblogs.com/jyan/archive/2012/07/23/2604474.html HtmlHelper用来在视图中呈现 HTML 控件. 以下列表显示了 ...